From eaef048980b8801cfbf5958e5cccb1c9a9e47935 Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Fri, 9 Jul 2004 17:27:56 +0000 Subject: [PATCH] added svgawin.c git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@734 423420c4-83ab-492f-b58f-81f9feb106b5 --- uiports/svgawin.c | 1843 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1843 insertions(+) create mode 100644 uiports/svgawin.c diff --git a/uiports/svgawin.c b/uiports/svgawin.c new file mode 100644 index 0000000..1042d33 --- /dev/null +++ b/uiports/svgawin.c @@ -0,0 +1,1843 @@ +/* -*- c-basic-offset: 8 -*- + rdesktop: A Remote Desktop Protocol client. + User interface services - SVGA lib + Copyright (C) Jay Sorg 2004 + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "../rdesktop.h" + +#include +#include +#include +#include + +#include // gethostname +#include // getpwuid +#include // va_list va_start va_end + + +extern int g_tcp_port_rdp; +int g_use_rdp5 = 0; +char g_hostname[16] = ""; +char g_username[64] = ""; +int g_height = 600; +int g_width = 800; +int g_server_bpp = 8; +int g_encryption = 1; +int g_desktop_save =1; +int g_bitmap_cache = 1; +int g_bitmap_cache_persist_enable = False; +int g_bitmap_cache_precache = True; +int g_bitmap_compression = 1; +int g_rdp5_performanceflags = 0; +int g_console_session = 0; +int g_keylayout = 0x409; /* Defaults to US keyboard layout */ + +/* hack globals */ +int g_argc = 0; +char** g_argv = 0; +int UpAndRunning = 0; +int g_sock = 0; +int deactivated = 0; +uint32 ext_disc_reason = 0; +char g_servername[128] = ""; +static uint32* colmap = 0; +static uint8* desk_save = 0; +static int g_server_Bpp = 1; + +// this is non null if vgalib has non accel functions available +// reading from video memory is sooo slow +static uint8* sdata = 0; +static int g_save_mem = 0; // for video memory use eg sdata == 0 + +// video acceleration +static int use_accel = 1; +static int has_fill_box = 0; +static int has_screen_copy = 0; +static int has_put_image = 0; + +// clip +int clip_startx; +int clip_starty; +int clip_endx; +int clip_endy; + +// mouse +uint8 mouse_under[32 * 32 * 4]; // save area under mouse +int mousex = 0; +int mousey = 0; +int mouseb = 0; + +// mouse info +typedef struct +{ + uint8 andmask[32 * 32]; + uint8 xormask[32 * 32]; + int x; + int y; + int w; + int h; +} tcursor; + +// mouse global +static tcursor mcursor; + +static int g_draw_mouse = 1; + +// bitmap +typedef struct +{ + int width; + int height; + uint8* data; + uint8 Bpp; +} bitmap; + +typedef struct +{ + int x; + int y; + int cx; + int cy; + void* prev; + void* next; +} myrect; + +myrect* head_rect = 0; + +//***************************************************************************** +// do a raster op +int rop(int rop, int src, int dst) +{ + switch (rop) + { + case 0x0: return 0; + case 0x1: return ~(src | dst); + case 0x2: return (~src) & dst; + case 0x3: return ~src; + case 0x4: return src & (~dst); + case 0x5: return ~(dst); + case 0x6: return src ^ dst; + case 0x7: return ~(src & dst); + case 0x8: return src & dst; + case 0x9: return ~(src) ^ dst; + case 0xa: return dst; + case 0xb: return (~src) | dst; + case 0xc: return src; + case 0xd: return src | (~dst); + case 0xe: return src | dst; + case 0xf: return ~0; + } + return dst; +} + +//***************************************************************************** +// get a screen pixel +int get_pixel(int x, int y) +{ + if (x >= 0 && x < g_width && y >= 0 && y < g_height) + { + if (sdata != 0) + { + if (g_server_Bpp == 1) + return sdata[y * g_width + x]; + else if (g_server_Bpp == 2) + return ((uint16*)sdata)[y * g_width + x]; + else + return 0; + } + else + return vga_getpixel(x, y); + } + else + return 0; +} + +//***************************************************************************** +// set a screen pixel +void set_pixel(int x, int y, int pixel, int op) +{ + if (x >= clip_startx && x < clip_endx && y >= clip_starty && y < clip_endy) + { + if (x >= 0 && x < g_width && y >= 0 && y < g_height) + { + if (op == 0x0) + pixel = 0; + else if (op == 0xf) + pixel = -1; + else if (op != 0xc) + pixel = rop(op, pixel, get_pixel(x, y)); + if (sdata != 0) + { + if (g_server_Bpp == 1) + sdata[y * g_width + x] = pixel; + else if (g_server_Bpp == 2) + ((uint16*)sdata)[y * g_width + x] = pixel; + } + else + { + vga_setcolor(pixel); + vga_drawpixel(x, y); + } + } + } +} + +//***************************************************************************** +// get a pixel from a bitmap +int get_pixel2(int x, int y, uint8* data, int width, int bpp) +{ + if (bpp == 8) + return data[y * width + x]; + else if (bpp == 16) + return ((uint16*)data)[y * width + x]; + else + return 0; +} + +//***************************************************************************** +// set a pixel in a bitmap +void set_pixel2(int x, int y, int pixel, uint8* data, int width, int bpp) +{ + if (bpp == 8) + data[y * width + x] = pixel; + else if (bpp == 16) + ((uint16*)data)[y * width + x] = pixel; +} + +//***************************************************************************** +// get a pointer into a bitmap +uint8* get_ptr(int x, int y, uint8* data, int width, int bpp) +{ + if (bpp == 8) + return data + (y * width + x); + else if (bpp == 16) + return data + (y * width + x) * 2; + else + return 0; +} + +//***************************************************************************** +// check if a certain pixel is set in a bitmap +BOOL is_pixel_on(uint8* data, int x, int y, int width, int bpp) +{ + int start; + int shift; + + if (bpp == 1) + { + width = (width + 7) / 8; + start = (y * width) + x / 8; + shift = x % 8; + return (data[start] & (0x80 >> shift)) != 0; + } + else if (bpp == 8) + { + return data[y * width + x] != 0; + } + else if (bpp == 24) + { + return data[(y * 3) * width + (x * 3)] != 0 && + data[(y * 3) * width + (x * 3) + 1] != 0 && + data[(y * 3) * width + (x * 3) + 2] != 0; + } + else + return False; +} + +//***************************************************************************** +void set_pixel_on(uint8* data, int x, int y, int width, int bpp, int pixel) +{ + if (bpp == 8) + { + data[y * width + x] = pixel; + } +} + +/*****************************************************************************/ +int warp_coords(int* x, int* y, int* cx, int* cy, int* srcx, int* srcy) +{ + int dx; + int dy; +// int lx = *x, ly = *y, lcx = *cx, lcy = *cy; + + if (clip_startx > *x) + dx = clip_startx - *x; + else + dx = 0; + if (clip_starty > *y) + dy = clip_starty - *y; + else + dy = 0; + if (*x + *cx > clip_endx) + *cx = (*cx - ((*x + *cx) - clip_endx)) /*+ 1*/; + if (*y + *cy > clip_endy) + *cy = (*cy - ((*y + *cy) - clip_endy)) /*+ 1*/; + *cx = *cx - dx; + *cy = *cy - dy; + if (*cx <= 0) + return False; + if (*cy <= 0) + return False; + *x = *x + dx; + *y = *y + dy; + if (srcx != NULL) + *srcx = *srcx + dx; + if (srcy != NULL) + *srcy = *srcy + dy; + +// if (*x != lx || *y != ly || *cx != lcx || *cy != lcy) +// printf("%d %d %d %d to %d %d %d %d\n", lx, ly, lcx, lcy, *x, *y, *cx, *cy); + + return True; +} + +//***************************************************************************** +void copy_mem(uint8* d, uint8* s, int n) +{ + while (n & (~7)) + { + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + *(d++) = *(s++); + n = n - 8; + } + while (n > 0) + { + *(d++) = *(s++); + n--; + } +} + +//***************************************************************************** +void copy_memb(uint8* d, uint8* s, int n) +{ + d = (d + n) - 1; + s = (s + n) - 1; + while (n & (~7)) + { + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + *(d--) = *(s--); + n = n - 8; + } + while (n > 0) + { + *(d--) = *(s--); + n--; + } +} + +//***************************************************************************** +// all in pixel except line_size is in bytes +void accel_draw_box(int x, int y, int cx, int cy, uint8* data, int line_size) +{ + int i; + uint8* s; + uint8* d; + + if (sdata != 0) + { + s = data; + d = get_ptr(x, y, sdata, g_width, g_server_bpp); + for (i = 0; i < cy; i++) + { + copy_mem(d, s, cx * g_server_Bpp); + s = s + line_size; + d = d + g_width * g_server_Bpp; + } + } + else if (has_put_image && line_size == cx * g_server_Bpp) + { + vga_accel(ACCEL_PUTIMAGE, x, y, cx, cy, data); + } + else + { + s = data; + for (i = 0; i < cy; i++) + { + vga_drawscansegment(s, x, y + i, cx * g_server_Bpp); + s = s + line_size; + } + } +} + +//***************************************************************************** +void accel_fill_rect(int x, int y, int cx, int cy, int color) +{ + int i; + uint8* temp; + uint8* d; + + if (sdata != 0) + { + temp = xmalloc(cx * g_server_Bpp); + if (g_server_Bpp == 1) + for (i = 0; i < cx; i++) + temp[i] = color; + else if (g_server_Bpp == 2) + for (i = 0; i < cx; i++) + ((uint16*)temp)[i] = color; + d = get_ptr(x, y, sdata, g_width, g_server_bpp); + for (i = 0; i < cy; i++) + { + copy_mem(d, temp, cx * g_server_Bpp); + d = d + g_width * g_server_Bpp; + } + xfree(temp); + } + else if (has_fill_box) + { + vga_accel(ACCEL_SETFGCOLOR, color); + vga_accel(ACCEL_FILLBOX, x, y, cx, cy); + } + else + { + temp = xmalloc(cx * g_server_Bpp); + if (g_server_Bpp == 1) + for (i = 0; i < cx; i++) + temp[i] = color; + else if (g_server_Bpp == 2) + for (i = 0; i < cx; i++) + ((uint16*)temp)[i] = color; + for (i = 0; i < cy; i++) + vga_drawscansegment(temp, x, y + i, cx * g_server_Bpp); + xfree(temp); + } +} + +//***************************************************************************** +void accel_screen_copy(int x, int y, int cx, int cy, int srcx, int srcy) +{ + uint8* temp; + uint8* s; + uint8* d; + int i; + + if (sdata != 0) + { + if (srcy < y) + { // bottom to top + s = get_ptr(srcx, (srcy + cy) - 1, sdata, g_width, g_server_bpp); + d = get_ptr(x, (y + cy) - 1, sdata, g_width, g_server_bpp); + for (i = 0; i < cy; i++) // copy down + { + copy_mem(d, s, cx * g_server_Bpp); + s = s - g_width * g_server_Bpp; + d = d - g_width * g_server_Bpp; + } + } + else if (srcy > y || srcx > x) // copy up or left + { // top to bottom + s = get_ptr(srcx, srcy, sdata, g_width, g_server_bpp); + d = get_ptr(x, y, sdata, g_width, g_server_bpp); + for (i = 0; i < cy; i++) + { + copy_mem(d, s, cx * g_server_Bpp); + s = s + g_width * g_server_Bpp; + d = d + g_width * g_server_Bpp; + } + } + else // copy straight right + { + s = get_ptr(srcx, srcy, sdata, g_width, g_server_bpp); + d = get_ptr(x, y, sdata, g_width, g_server_bpp); + for (i = 0; i < cy; i++) + { + copy_memb(d, s, cx * g_server_Bpp); + s = s + g_width * g_server_Bpp; + d = d + g_width * g_server_Bpp; + } + } + } + else if (has_screen_copy) + { + vga_accel(ACCEL_SCREENCOPY, srcx, srcy, x, y, cx, cy); + } + else + { + // slow + temp = (uint8*)xmalloc(cx * cy * g_server_Bpp); + for (i = 0; i < cy; i++) + vga_getscansegment(get_ptr(0, i, temp, cx, g_server_bpp), srcx, srcy + i, cx * g_server_Bpp); + for (i = 0; i < cy; i++) + vga_drawscansegment(get_ptr(0, i, temp, cx, g_server_bpp), x, y + i, cx * g_server_Bpp); + xfree(temp); + } +} + +//***************************************************************************** +// return bool +int contains_mouse(int x, int y, int cx, int cy) +{ + if (mousex + 32 >= x && + mousey + 32 >= y && + mousex <= x + cx && + mousey <= y + cy) + return 1; + else + return 0; +} + +//***************************************************************************** +void fill_rect(int x, int y, int cx, int cy, int colour, int opcode) +{ + int i; + int j; + + if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + { + if (opcode == 0xc) + accel_fill_rect(x, y, cx, cy, colour); + else if (opcode == 0xf) + accel_fill_rect(x, y, cx, cy, -1); + else if (opcode == 0x0) + accel_fill_rect(x, y, cx, cy, 0); + else + { + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, colour, opcode); + } + } +} + +//***************************************************************************** +void get_rect(int x, int y, int cx, int cy, uint8* p) +{ + int i; + + if (x < 0) + { + cx = cx + x; + x = 0; + } + if (y < 0) + { + cy = cy + y; + y = 0; + } + if (sdata != 0) + { + for (i = 0; i < cy; i++) + { + copy_mem(p, get_ptr(x, y + i, sdata, g_width, g_server_bpp), cx * g_server_Bpp); + p = p + cx * g_server_Bpp; + } + } + else + { + for (i = 0; i < cy; i++) + { + vga_getscansegment(p, x, y + i, cx * g_server_Bpp); + p = p + cx * g_server_Bpp; + } + } +} + +/*****************************************************************************/ +// return true if r1 is contained by r2 +int is_contained_by(myrect* r1, myrect* r2) +{ + if (r1->x >= r2->x && + r1->y >= r2->y && + r1->x + r1->cx <= r2->x + r2->cx && + r1->y + r1->cy <= r2->y + r2->cy) + return 1; + else + return 0; +} + +/*****************************************************************************/ +void draw_cursor_under(int ox, int oy) +{ + int i; + int j; + int k; + uint8* ptr; + int len; + + if (ox < 0) + k = -ox; + else + k = 0; + j = g_width - ox; + if (j > 32) + j = 32; + if (j > 0) + { + for (i = 0; i < 32; i++) + { + ptr = get_ptr(k, i, mouse_under, 32, g_server_bpp); + len = (j - k) * g_server_Bpp; + if (ox + k >= 0 && oy + i >= 0 && ox + k < g_width && oy + i < g_height) + vga_drawscansegment(ptr, ox + k, oy + i, len); + } + } + g_draw_mouse = 1; +} + +/*****************************************************************************/ +void draw_cursor(void) +{ + int i; + int j; + int k; + int pixel; + uint8 mouse_a[32 * 32 * 4]; + uint8* ptr; + int len; + + if (!g_draw_mouse) + return; + memset(mouse_under, 0, sizeof(mouse_under)); + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + pixel = get_pixel(mousex + j, mousey + i); + set_pixel2(j, i, pixel, mouse_under, 32, g_server_bpp); + if (mcursor.andmask[i * 32 + j] == 0) + k = 0; + else + k = ~0; + pixel = rop(0x8, k, pixel); + if (mcursor.xormask[i * 32 + j] == 0) + k = 0; + else + k = ~0; + pixel = rop(0x6, k, pixel); + set_pixel2(j, i, pixel, mouse_a, 32, g_server_bpp); + } + } + if (mousex < 0) + k = -mousex; + else + k = 0; + j = g_width - mousex; + if (j > 32) + j = 32; + if (j > 0) + { + for (i = mousey; i < mousey + 32; i++) + if (i < g_height && i >= 0) + { + ptr = get_ptr(k, i - mousey, mouse_a, 32, g_server_bpp); + len = (j - k) * g_server_Bpp; + vga_drawscansegment(ptr, mousex + k, i, len); + } + } + g_draw_mouse = 0; +} + +/*****************************************************************************/ +// add a rect to cache +void cache_rect(int x, int y, int cx, int cy, int do_warp) +{ + myrect* rect; + myrect* walk_rect; + + if (sdata == 0) + { + draw_cursor(); + return; + } + if (do_warp) + if (!warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + return; + rect = (myrect*)xmalloc(sizeof(myrect)); + rect->x = x; + rect->y = y; + rect->cx = cx; + rect->cy = cy; + rect->next = 0; + rect->prev = 0; + if (head_rect == 0) + head_rect = rect; + else + { + walk_rect = 0; + do + { + if (walk_rect == 0) + walk_rect = head_rect; + else + walk_rect = walk_rect->next; + if (is_contained_by(rect, walk_rect)) + { + xfree(rect); + return; + } + } + while (walk_rect->next != 0); + walk_rect->next = rect; + rect->prev = walk_rect; + } +} + +//***************************************************************************** +void draw_cache_rects(void) +{ + int i; + myrect* rect; + myrect* rect1; + uint8* p; + + // draw all the rects + rect = head_rect; + while (rect != 0) + { + p = get_ptr(rect->x, rect->y, sdata, g_width, g_server_bpp); + for (i = 0; i < rect->cy; i++) + { + vga_drawscansegment(p, rect->x, rect->y + i, rect->cx * g_server_Bpp); + p = p + g_width * g_server_Bpp; + } + rect1 = rect; + rect = rect->next; + xfree(rect1); + } + head_rect = 0; +} + +/*****************************************************************************/ +void key_event(int scancode, int pressed) +{ + int rdpkey; + int ext; + + if (!UpAndRunning) + return; + rdpkey = scancode; + ext = 0; + switch (scancode) + { + case SCANCODE_CURSORBLOCKUP: rdpkey = 0xc8; ext = KBD_FLAG_EXT; break; // up arrow + case SCANCODE_CURSORBLOCKDOWN: rdpkey = 0xd0; ext = KBD_FLAG_EXT; break; // down arrow + case SCANCODE_CURSORBLOCKRIGHT: rdpkey = 0xcd; ext = KBD_FLAG_EXT; break; // right arrow + case SCANCODE_CURSORBLOCKLEFT: rdpkey = 0xcb; ext = KBD_FLAG_EXT; break; // left arrow + case SCANCODE_PAGEDOWN: rdpkey = 0xd1; ext = KBD_FLAG_EXT; break; // page down + case SCANCODE_PAGEUP: rdpkey = 0xc9; ext = KBD_FLAG_EXT; break; // page up + case SCANCODE_HOME: rdpkey = 0xc7; ext = KBD_FLAG_EXT; break; // home + case SCANCODE_END: rdpkey = 0xcf; ext = KBD_FLAG_EXT; break; // end + case SCANCODE_INSERT: rdpkey = 0xd2; ext = KBD_FLAG_EXT; break; // insert + case SCANCODE_REMOVE: rdpkey = 0xd3; ext = KBD_FLAG_EXT; break; // delete + case SCANCODE_KEYPADDIVIDE: rdpkey = 0x35; break; // / + case SCANCODE_KEYPADENTER: rdpkey = 0x1c; break; // enter + case SCANCODE_RIGHTCONTROL: rdpkey = 0x1d; break; // right ctrl + case SCANCODE_RIGHTALT: rdpkey = 0x38; break; // right alt + case SCANCODE_LEFTWIN: rdpkey = 0; break; // left win + case SCANCODE_RIGHTWIN: rdpkey = 0; break; // right win + case 127: rdpkey = 0; break; // menu key + case SCANCODE_PRINTSCREEN: rdpkey = 0; break; // print screen + case SCANCODE_BREAK: rdpkey = 0; break; // break + case SCANCODE_SCROLLLOCK: rdpkey = 0; break; // scroll lock + case 112: // mouse down + { + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON4, + mouse_getx(), mouse_gety()); + return; + } + case 113: // mouse up + { + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON5, + mouse_getx(), mouse_gety()); + return; + } + } +// printf("%d %d\n", scancode, pressed); + if (pressed) + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYPRESS | ext, rdpkey, 0); + else + rdp_send_input(0, RDP_INPUT_SCANCODE, RDP_KEYRELEASE | ext, rdpkey, 0); + +} + +/*****************************************************************************/ +int ui_init(void) +{ + vga_init(); + memset(&mcursor, 0, sizeof(tcursor)); + desk_save = (uint8*)xmalloc(0x38400 * g_server_Bpp); + return 1; +} + +/*****************************************************************************/ +void ui_deinit(void) +{ + xfree(desk_save); +} + +/*****************************************************************************/ +int ui_create_window(void) +{ + int vgamode; + int i; + + vgamode = G800x600x256; + if (g_width == 640 && g_height == 480) + { + if (g_server_Bpp == 1) + vgamode = G640x480x256; + else if (g_server_Bpp == 2) + vgamode = G640x480x64K; + } + else if (g_width == 800 && g_height == 600) + { + if (g_server_Bpp == 1) + vgamode = G800x600x256; + else if (g_server_Bpp == 2) + vgamode = G800x600x64K; + } + else if (g_width == 1024 && g_height == 768) + { + if (g_server_Bpp == 1) + vgamode = G1024x768x256; + else if (g_server_Bpp == 2) + vgamode = G1024x768x64K; + } + else + { + error("Invalid width / height"); + return 0; + } + ui_reset_clip(); + if (!vga_hasmode(vgamode)) + { + error("Graphics unavailable"); + return 0; + } + vga_setmousesupport(1); + mouse_setposition(g_width / 2, g_height / 2); + vga_setmode(vgamode); + if (keyboard_init()) + { + error("Keyboard unavailable"); + return 0; + } + keyboard_seteventhandler(key_event); + if (use_accel) + { + i = vga_ext_set(VGA_EXT_AVAILABLE, VGA_AVAIL_ACCEL); + if (i & ACCELFLAG_PUTIMAGE) + has_put_image = 1; + if (i & ACCELFLAG_SCREENCOPY) + has_screen_copy = 1; + if (i & ACCELFLAG_FILLBOX) + has_fill_box = 1; + printf("accel %d\n", i); + } + if (!has_screen_copy && !g_save_mem) + sdata = xmalloc(g_width * g_height * g_server_Bpp); + return 1; +} + +/*****************************************************************************/ +void ui_destroy_window(void) +{ + keyboard_close(); /* Don't forget this! */ + vga_setmode(TEXT); + if (sdata != 0) + xfree(sdata); +} + +/*****************************************************************************/ +void process_mouse(void) +{ + int ox = mousex; + int oy = mousey; + int ob = mouseb; + + if (!UpAndRunning) + return; + mousex = mouse_getx() - mcursor.x; + mousey = mouse_gety() - mcursor.y; + mouseb = mouse_getbutton(); + + if (mouseb != ob) // button + { + // right button + if (mouseb & 1) + if (!(ob & 1)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON2, + mousex + mcursor.x, mousey + mcursor.y); + if (ob & 1) + if (!(mouseb & 1)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, + mousex + mcursor.x, mousey + mcursor.y); + // middle button + if (mouseb & 2) + if (!(ob & 2)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON3, + mousex + mcursor.x, mousey + mcursor.y); + if (ob & 2) + if (!(mouseb & 2)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, + mousex + mcursor.x, mousey + mcursor.y); + // left button + if (mouseb & 4) + if (!(ob & 4)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_DOWN | MOUSE_FLAG_BUTTON1, + mousex + mcursor.x, mousey + mcursor.y); + if (ob & 4) + if (!(mouseb & 4)) + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, + mousex + mcursor.x, mousey + mcursor.y); + } + if (mousex != ox || mousey != oy) // movement + { + rdp_send_input(0, RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, + mousex + mcursor.x, mousey + mcursor.y); + draw_cursor_under(ox, oy); + draw_cursor(); + } +} + +/*****************************************************************************/ +void process_keyboard(void) +{ + if (!UpAndRunning) + return; +} + +/*****************************************************************************/ +BOOL ui_main_loop(void) +{ + int sel; + fd_set rfds; + + if (!rdp_connect(g_servername, RDP_LOGON_NORMAL, "", "", "", "")) + return False; + UpAndRunning = 1; + FD_ZERO(&rfds); + FD_SET(g_sock, &rfds); + sel = vga_waitevent(3, &rfds, NULL, NULL, NULL); + while (sel >= 0) + { + if (sel & 1) /* mouse */ + { + process_mouse(); + } + else if (sel & 2) /* keyboard */ + { + process_keyboard(); + } + else + { + if (!rdp_loop(&deactivated, &ext_disc_reason)) + return True; /* ok */ + } + FD_ZERO(&rfds); + FD_SET(g_sock, &rfds); + sel = vga_waitevent(3, &rfds, NULL, NULL, NULL); + } + return True; +} + +/*****************************************************************************/ +void ui_bell(void) +{ +} + +/*****************************************************************************/ +int ui_select(int in) +{ + g_sock = in; + return 1; +} + +/*****************************************************************************/ +void* ui_create_glyph(int width, int height, uint8* data) +{ + int i, j; + uint8* glyph_data; + bitmap* the_glyph; + + glyph_data = (uint8*)xmalloc(width * height); + the_glyph = (bitmap*)xmalloc(sizeof(bitmap)); + the_glyph->width = width; + the_glyph->height = height; + the_glyph->data = glyph_data; + memset(glyph_data, 0, width * height); + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + if (is_pixel_on(data, j, i, width, 1)) + set_pixel_on(glyph_data, j, i, width, 8, 255); + return the_glyph; +} + +/*****************************************************************************/ +void ui_destroy_glyph(void* glyph) +{ + bitmap* the_glyph; + + the_glyph = (bitmap*)glyph; + if (the_glyph != NULL) + { + if (the_glyph->data != NULL) + xfree(the_glyph->data); + xfree(the_glyph); + } +} + +/*****************************************************************************/ +void ui_destroy_bitmap(void* bmp) +{ + bitmap* b; + + b = (bitmap*)bmp; + xfree(b->data); + xfree(b); +} + +/*****************************************************************************/ +void ui_reset_clip(void) +{ + clip_startx = 0; + clip_starty = 0; + clip_endx = g_width; + clip_endy = g_height; +} + +/*****************************************************************************/ +void ui_set_clip(int x, int y, int cx, int cy) +{ + clip_startx = x; + clip_starty = y; + clip_endx = x + cx; + clip_endy = y + cy; +} + +/*****************************************************************************/ +void* ui_create_colourmap(COLOURMAP * colours) +{ + int i = 0; + int n = colours->ncolours; + COLOURENTRY* c = colours->colours; + int* cmap = (int*)xmalloc(3 * 256 * sizeof (int)); + if (n > 256) + n = 256; + bzero(cmap, 256 * 3 * sizeof (int)); + for (i = 0; i < (3 * n); c++) + { + cmap[i++] = (c->red) >> 2; + cmap[i++] = (c->green) >> 2; + cmap[i++] = (c->blue) >> 2; + } + return cmap; +} + +/*****************************************************************************/ +void ui_destroy_colourmap(HCOLOURMAP map) +{ + if (colmap == map) + colmap = 0; + xfree(map); +} + +/*****************************************************************************/ +void ui_set_colourmap(void* map) +{ + if (colmap != 0) + xfree(colmap); + vga_setpalvec(0, 256, (int*)map); + colmap = map; +} + +/*****************************************************************************/ +HBITMAP ui_create_bitmap(int width, int height, uint8* data) +{ + bitmap* b; + + b = (bitmap*)xmalloc(sizeof(bitmap)); + b->data = (uint8*)xmalloc(width * height * g_server_Bpp); + b->width = width; + b->height = height; + b->Bpp = g_server_Bpp; + copy_mem(b->data, data, width * height * g_server_Bpp); + return (void*)b; +} + +//***************************************************************************** +void draw_glyph (int x, int y, HGLYPH glyph, int fgcolour) +{ + bitmap* the_glyph; + int i, j; + + the_glyph = (bitmap*)glyph; + if (the_glyph == NULL) + return; + for (i = 0; i < the_glyph->height; i++) + for (j = 0; j < the_glyph->width; j++) + if (is_pixel_on(the_glyph->data, j, i, the_glyph->width, 8)) + set_pixel(x + j, y + i, fgcolour, 0xc); +} + +#define DO_GLYPH(ttext,idx) \ +{\ + glyph = cache_get_font (font, ttext[idx]);\ + if (!(flags & TEXT2_IMPLICIT_X))\ + {\ + xyoffset = ttext[++idx];\ + if ((xyoffset & 0x80))\ + {\ + if (flags & TEXT2_VERTICAL) \ + y += ttext[idx+1] | (ttext[idx+2] << 8);\ + else\ + x += ttext[idx+1] | (ttext[idx+2] << 8);\ + idx += 2;\ + }\ + else\ + {\ + if (flags & TEXT2_VERTICAL) \ + y += xyoffset;\ + else\ + x += xyoffset;\ + }\ + }\ + if (glyph != NULL)\ + {\ + draw_glyph (x + glyph->offset, y + glyph->baseline, glyph->pixmap, fgcolour);\ + if (flags & TEXT2_IMPLICIT_X)\ + x += glyph->width;\ + }\ +} + +/*****************************************************************************/ +void ui_draw_text(uint8 font, uint8 flags, int mixmode, + int x, int y, + int clipx, int clipy, int clipcx, int clipcy, + int boxx, int boxy, int boxcx, int boxcy, + int bgcolour, int fgcolour, uint8* text, uint8 length) +{ + int i; + int j; + int xyoffset; + DATABLOB* entry; + FONTGLYPH* glyph; + + if (boxcx > 1) + { + if (contains_mouse(boxx, boxy, boxcx, boxcy)) + draw_cursor_under(mousex, mousey); + fill_rect(boxx, boxy, boxcx, boxcy, bgcolour, 0xc); + } + else + { + if (contains_mouse(clipx, clipy, clipcx, clipcy)) + draw_cursor_under(mousex, mousey); + if (mixmode == MIX_OPAQUE) + fill_rect(clipx, clipy, clipcx, clipcy, bgcolour, 0xc); + } + + /* Paint text, character by character */ + for (i = 0; i < length;) + { + switch (text[i]) + { + case 0xff: + if (i + 2 < length) + cache_put_text(text[i + 1], text, text[i + 2]); + else + { + error("this shouldn't be happening\n"); + exit(1); + } + /* this will move pointer from start to first character after FF command */ + length -= i + 3; + text = &(text[i + 3]); + i = 0; + break; + + case 0xfe: + entry = cache_get_text(text[i + 1]); + if (entry != NULL) + { + if ((((uint8 *) (entry->data))[1] == 0) && (!(flags & TEXT2_IMPLICIT_X))) + { + if (flags & TEXT2_VERTICAL) + y += text[i + 2]; + else + x += text[i + 2]; + } + for (j = 0; j < entry->size; j++) + DO_GLYPH(((uint8 *) (entry->data)), j); + } + if (i + 2 < length) + i += 3; + else + i += 2; + length -= i; + /* this will move pointer from start to first character after FE command */ + text = &(text[i]); + i = 0; + break; + + default: + DO_GLYPH(text, i); + i++; + break; + } + } + if (boxcx > 1) + cache_rect(boxx, boxy, boxcx, boxcy, True); + else + cache_rect(clipx, clipy, clipcx, clipcy, True); +} + +//***************************************************************************** +// Bresenham's line drawing algorithm +void ui_line(uint8 opcode, int startx, int starty, int endx, + int endy, PEN* pen) +{ + int dx; + int dy; + int incx; + int incy; + int dpr; + int dpru; + int p; + int left; + int top; + int right; + int bottom; + + if (startx > endx) + { + dx = startx - endx; + incx = -1; + left = endx; + right = startx; + } + else + { + dx = endx - startx; + incx = 1; + left = startx; + right = endx; + } + if (starty > endy) + { + dy = starty - endy; + incy = -1; + top = endy; + bottom = starty; + } + else + { + dy = endy - starty; + incy = 1; + top = starty; + bottom = endy; + } + if (contains_mouse(left, top, (right - left) + 1, (bottom - top) + 1)) + draw_cursor_under(mousex, mousey); + if (dx >= dy) + { + dpr = dy << 1; + dpru = dpr - (dx << 1); + p = dpr - dx; + for (; dx >= 0; dx--) + { + set_pixel(startx, starty, pen->colour, opcode); + if (p > 0) + { + startx += incx; + starty += incy; + p += dpru; + } + else + { + startx += incx; + p += dpr; + } + } + } + else + { + dpr = dx << 1; + dpru = dpr - (dy << 1); + p = dpr - dy; + for (; dy >= 0; dy--) + { + set_pixel(startx, starty, pen->colour, opcode); + if (p > 0) + { + startx += incx; + starty += incy; + p += dpru; + } + else + { + starty += incy; + p += dpr; + } + } + } + cache_rect(left, top, (right - left) + 1, (bottom - top) + 1, True); +} + +/*****************************************************************************/ +void ui_triblt(uint8 opcode, int x, int y, int cx, int cy, + HBITMAP src, int srcx, int srcy, + BRUSH* brush, int bgcolour, int fgcolour) +{ + // non used +} + +/*****************************************************************************/ +void ui_memblt(uint8 opcode, int x, int y, int cx, int cy, + HBITMAP src, int srcx, int srcy) +{ + bitmap* b; + int i; + int j; + int pixel; + + if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy)) + { + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + b = (bitmap*)src; + if (opcode == 0xc) + accel_draw_box(x, y, cx, cy, get_ptr(srcx, srcy, b->data, b->width, g_server_bpp), + b->width * g_server_Bpp); + else + { + for (i = 0; i < cy; i++) + { + for (j = 0; j < cx; j++) + { + pixel = get_pixel2(srcx + j, srcy + i, b->data, b->width, g_server_bpp); + set_pixel(x + j, y + i, pixel, opcode); + } + } + } + cache_rect(x, y, cx, cy, False); + } +} + +/*****************************************************************************/ +void ui_desktop_restore(uint32 offset, int x, int y, int cx, int cy) +{ + uint8* p; + + if (offset > 0x38400) + offset = 0; + if (offset + cx * cy > 0x38400) + return; + p = desk_save + offset * g_server_Bpp; + ui_paint_bitmap(x, y, cx, cy, cx, cy, p); +} + +/*****************************************************************************/ +void ui_desktop_save(uint32 offset, int x, int y, int cx, int cy) +{ + uint8* p; + + if (offset > 0x38400) + offset = 0; + if (offset + cx * cy > 0x38400) + return; + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + p = desk_save + offset * g_server_Bpp; + get_rect(x, y, cx, cy, p); +} + +/*****************************************************************************/ +void ui_rect(int x, int y, int cx, int cy, int colour) +{ + if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + { + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + accel_fill_rect(x, y, cx, cy, colour); + cache_rect(x, y, cx, cy, False); + } +} + +/*****************************************************************************/ +void ui_screenblt(uint8 opcode, int x, int y, int cx, int cy, + int srcx, int srcy) +{ + int i; + int j; + uint8* temp; + + if (x == srcx && y == srcy) + return; + if (warp_coords(&x, &y, &cx, &cy, &srcx, &srcy)) + { + if (contains_mouse(x, y, cx, cy) || contains_mouse(srcx, srcy, cx, cy)) + draw_cursor_under(mousex, mousey); + if (opcode == 0xc) /* copy */ + accel_screen_copy(x, y, cx, cy, srcx, srcy); + else + { + temp = (uint8*)xmalloc(cx * cy * g_server_Bpp); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel2(j, i, get_pixel(srcx + j, srcy + i), temp, cx, g_server_bpp); + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + set_pixel(x + j, y + i, get_pixel2(j, i, temp, cx, g_server_bpp), opcode); + xfree(temp); + } + cache_rect(x, y, cx, cy, False); + draw_cache_rects(); // draw them all so screen is not jumpy + } +} + +/*****************************************************************************/ +void ui_patblt(uint8 opcode, int x, int y, int cx, int cy, + BRUSH * brush, int bgcolour, int fgcolour) +{ + int i; + int j; + uint8 ipattern[8]; + + if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + { + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + switch (brush->style) + { + case 0: + fill_rect(x, y, cx, cy, fgcolour, opcode); + break; + case 3: + for (i = 0; i < 8; i++) + ipattern[i] = ~brush->pattern[7 - i]; + for (i = 0; i < cy; i++) + for (j = 0; j < cx; j++) + if (is_pixel_on(ipattern, (x + j + brush->xorigin) % 8, + (y + i + brush->yorigin) % 8, 8, 1)) + set_pixel(x + j, y + i, fgcolour, opcode); + else + set_pixel(x + j, y + i, bgcolour, opcode); + break; + } + cache_rect(x, y, cx, cy, False); + } +} + +/*****************************************************************************/ +void ui_destblt(uint8 opcode, int x, int y, int cx, int cy) +{ + if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + { + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + fill_rect(x, y, cx, cy, -1, opcode); + cache_rect(x, y, cx, cy, False); + } +} + +/*****************************************************************************/ +void ui_move_pointer(int x, int y) +{ +} + +/*****************************************************************************/ +void ui_set_null_cursor(void) +{ + draw_cursor_under(mousex, mousey); + mousex = mousex - mcursor.x; + mousey = mousey - mcursor.y; + memset(&mcursor, 0, sizeof(mcursor)); + memset(mcursor.andmask, 255, sizeof(mcursor.andmask)); + memset(mcursor.xormask, 0, sizeof(mcursor.xormask)); + draw_cursor(); +} + +/*****************************************************************************/ +void ui_paint_bitmap(int x, int y, int cx, int cy, + int width, int height, uint8* data) +{ + if (warp_coords(&x, &y, &cx, &cy, NULL, NULL)) + { + if (contains_mouse(x, y, cx, cy)) + draw_cursor_under(mousex, mousey); + accel_draw_box(x, y, cx, cy, data, width * g_server_Bpp); + cache_rect(x, y, cx, cy, False); + } +} + +/*****************************************************************************/ +void* ui_create_cursor(unsigned int x, unsigned int y, + int width, int height, + uint8* andmask, uint8* xormask) +{ + tcursor* c; + int i; + int j; + + c = (tcursor*)xmalloc(sizeof(tcursor)); + memset(c, 0, sizeof(tcursor)); + c->w = width; + c->h = height; + c->x = x; + c->y = y; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 32; j++) + { + if (is_pixel_on(andmask, j, i, 32, 1)) + set_pixel_on(c->andmask, j, 31 - i, 32, 8, 255); + if (is_pixel_on(xormask, j, i, 32, 24)) + set_pixel_on(c->xormask, j, 31 - i, 32, 8, 255); + } + } + return (void*)c; +} + +/*****************************************************************************/ +void ui_destroy_cursor(void* cursor) +{ + if (cursor != NULL) + xfree(cursor); +} + +/*****************************************************************************/ +void ui_set_cursor(void* cursor) +{ + int x; + int y; + int ox; + int oy; + + ox = mousex; + oy = mousey; + x = mousex + mcursor.x; + y = mousey + mcursor.y; + memcpy(&mcursor, cursor, sizeof(tcursor)); + mousex = x - mcursor.x; + mousey = y - mcursor.y; + draw_cursor_under(ox, oy); + draw_cursor(); +} + +/*****************************************************************************/ +uint16 ui_get_numlock_state(unsigned int state) +{ + return 0; +} + +/*****************************************************************************/ +unsigned int read_keyboard_state(void) +{ + return 0; +} + +/*****************************************************************************/ +void ui_resize_window(void) +{ +} + +/*****************************************************************************/ +void ui_begin_update(void) +{ +} + +/*****************************************************************************/ +void ui_end_update(void) +{ + draw_cache_rects(); + draw_cursor(); +} + +/*****************************************************************************/ +void generate_random(uint8* random) +{ + memcpy(random, "12345678901234567890123456789012", 32); +} + +/*****************************************************************************/ +void save_licence(uint8* data, int length) +{ +} + +/*****************************************************************************/ +int load_licence(uint8** data) +{ + return 0; +} + +/*****************************************************************************/ +void* xrealloc(void* in_val, int size) +{ + return realloc(in_val, size); +} + +/*****************************************************************************/ +void* xmalloc(int size) +{ + return malloc(size); +} + +/*****************************************************************************/ +void xfree(void* in_val) +{ + free(in_val); +} + +/*****************************************************************************/ +void warning(char* format, ...) +{ + va_list ap; + + fprintf(stderr, "WARNING: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} + +/*****************************************************************************/ +void unimpl(char* format, ...) +{ + va_list ap; + + fprintf(stderr, "NOT IMPLEMENTED: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} + +/*****************************************************************************/ +void error(char* format, ...) +{ + va_list ap; + + fprintf(stderr, "ERROR: "); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); +} + +BOOL rd_pstcache_mkdir(void) +{ + return 0; +} + +/*****************************************************************************/ +int rd_open_file(char *filename) +{ + return 0; +} + +/*****************************************************************************/ +void rd_close_file(int fd) +{ + return; +} + +/*****************************************************************************/ +int rd_read_file(int fd, void *ptr, int len) +{ + return 0; +} + +/*****************************************************************************/ +int rd_write_file(int fd, void* ptr, int len) +{ + return 0; +} + +/*****************************************************************************/ +int rd_lseek_file(int fd, int offset) +{ + return 0; +} + +/*****************************************************************************/ +BOOL rd_lock_file(int fd, int start, int len) +{ + return False; +} + +/*****************************************************************************/ +void get_username_and_hostname(void) +{ + char fullhostname[64]; + char* p; + struct passwd* pw; + + STRNCPY(g_username, "unknown", sizeof(g_username)); + STRNCPY(g_hostname, "unknown", sizeof(g_hostname)); + pw = getpwuid(getuid()); + if (pw != NULL && pw->pw_name != NULL) + { + STRNCPY(g_username, pw->pw_name, sizeof(g_username)); + } + if (gethostname(fullhostname, sizeof(fullhostname)) != -1) + { + p = strchr(fullhostname, '.'); + if (p != NULL) + *p = 0; + STRNCPY(g_hostname, fullhostname, sizeof(g_hostname)); + } +} + +/*****************************************************************************/ +void out_params(void) +{ + fprintf(stderr, "rdesktop: A Remote Desktop Protocol client.\n"); + fprintf(stderr, "Version " VERSION ". Copyright (C) 1999-2003 Matt Chapman.\n"); + fprintf(stderr, "See http://www.rdesktop.org/ for more information.\n\n"); + fprintf(stderr, "Usage: svgardesktop [options] server\n"); + fprintf(stderr, " -g: desktop geometry (WxH)\n"); + fprintf(stderr, " -4: use RDP version 4\n"); + fprintf(stderr, " -5: use RDP version 5 (default)\n"); + fprintf(stderr, " -t: tcp port\n"); + fprintf(stderr, " -u: user name\n"); + fprintf(stderr, " -n: client hostname\n"); + fprintf(stderr, " -d: disable accel funcs\n"); + fprintf(stderr, " -a: connection colour depth\n"); + fprintf(stderr, " -l: low memory\n"); + fprintf(stderr, "\n"); +} + +/* produce a hex dump */ +void hexdump(uint8* p, uint32 len) +{ + uint8* line; + int i; + int thisline; + int offset; + + line = p; + offset = 0; + while (offset < len) + { + printf("%04x ", offset); + thisline = len - offset; + if (thisline > 16) + thisline = 16; + + for (i = 0; i < thisline; i++) + printf("%02x ", line[i]); + + for (; i < 16; i++) + printf(" "); + + for (i = 0; i < thisline; i++) + printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + + printf("\n"); + offset += thisline; + line += thisline; + } +} + +/*****************************************************************************/ +int parse_parameters(int in_argc, char** in_argv) +{ + int i; + char* p; + + if (in_argc <= 1) + { + out_params(); + return 0; + } + g_argc = in_argc; + g_argv = in_argv; + for (i = 1; i < in_argc; i++) + { + strcpy(g_servername, in_argv[i]); + if (strcmp(in_argv[i], "-g") == 0) + { + g_width = strtol(in_argv[i + 1], &p, 10); + if (g_width <= 0) + { + error("invalid geometry\n"); + return 0; + } + if (*p == 'x') + g_height = strtol(p + 1, NULL, 10); + if (g_height <= 0) + { + error("invalid geometry\n"); + return 0; + } + g_width = (g_width + 3) & ~3; + } + else if (strcmp(in_argv[i], "-4") == 0) + g_use_rdp5 = 0; + else if (strcmp(in_argv[i], "-5") == 0) + g_use_rdp5 = 1; + else if (strcmp(in_argv[i], "-t") == 0) + g_tcp_port_rdp = strtol(in_argv[i + 1], &p, 10); + else if (strcmp(in_argv[i], "-h") == 0) + { + out_params(); + return 0; + } + else if (strcmp(in_argv[i], "-n") == 0) + { + STRNCPY(g_hostname, in_argv[i + 1], sizeof(g_hostname)); + } + else if (strcmp(in_argv[i], "-u") == 0) + { + STRNCPY(g_username, in_argv[i + 1], sizeof(g_username)); + } + else if (strcmp(in_argv[i], "-d") == 0) + { + use_accel = 0; + } + else if (strcmp(in_argv[i], "-a") == 0) + { + g_server_bpp = strtol(in_argv[i + 1], NULL, 10); + if (g_server_bpp != 8 && g_server_bpp != 16) + { + error("invalid server bpp\n"); + return 0; + } + g_server_Bpp = (g_server_bpp + 7) / 8; + } + else if (strcmp(in_argv[i], "-l") == 0) + g_save_mem = 1; + } + return 1; +} + +/*****************************************************************************/ +int main(int in_argc, char** in_argv) +{ + get_username_and_hostname(); + if (!parse_parameters(in_argc, in_argv)) + return 0; + if (!ui_init()) + return 1; + if (!ui_create_window()) + return 1; + ui_main_loop(); + ui_destroy_window(); + ui_deinit(); + return 0; +}