Another major change round. VNC moved to top level. More cleanups of global data, all VM processing now handled in pc.c (out of the platforms, yay!), and some video cleanups. This build MAY have issues with window sizes, resizing, and fullscreen will not work until the next build- sorry.
This commit is contained in:
370
src/vnc.c
Normal file
370
src/vnc.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Implement the VNC remote renderer with LibVNCServer.
|
||||
*
|
||||
* Version: @(#)lnx_vnc.c 1.0.4 2017/10/18
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Based on raw code by RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "86box.h"
|
||||
#include "device.h"
|
||||
#include "video/video.h"
|
||||
#include "plat.h"
|
||||
#include "plat_keyboard.h"
|
||||
#include "plat_mouse.h"
|
||||
#include "ui.h"
|
||||
#define BITMAP MY_BITMAP
|
||||
#include <rfb/rfb.h>
|
||||
#undef BITMAP
|
||||
#include "vnc.h"
|
||||
|
||||
|
||||
#define VNC_MIN_X 320
|
||||
#define VNC_MAX_X 2048
|
||||
#define VNC_MIN_Y 200
|
||||
#define VNC_MAX_Y 2048
|
||||
|
||||
|
||||
static rfbScreenInfoPtr rfb = NULL;
|
||||
static int clients;
|
||||
static int updatingSize;
|
||||
static int allowedX,
|
||||
allowedY;
|
||||
|
||||
static int keysyms_00[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00-07
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 08-0f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10-17
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 18-1f
|
||||
0x0039, 0x2a02, 0x2a28, 0x2a04, 0x2a05, 0x2a06, 0x2a08, 0x0028, // 20-27
|
||||
0x2a0a, 0x2a0b, 0x2a09, 0x2a0d, 0x0033, 0x000c, 0x0034, 0x0035, // 28-2f
|
||||
0x000b, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, // 30-37
|
||||
0x0009, 0x000a, 0x2a27, 0x0027, 0x2a33, 0x000d, 0x2a34, 0x2a35, // 38-3f
|
||||
0x2a03, 0x2a1e, 0x2a30, 0x2a2e, 0x2a20, 0x2a12, 0x2a21, 0x2a22, // 40-47
|
||||
0x2a23, 0x2a17, 0x2a24, 0x2a25, 0x2a26, 0x2a32, 0x2a31, 0x2a18, // 48-4f
|
||||
0x2a19, 0x2a10, 0x2a13, 0x2a1f, 0x2a14, 0x2a16, 0x2a2f, 0x2a11, // 50-57
|
||||
0x2a2d, 0x2a15, 0x2a2c, 0x001a, 0x0000, 0x001b, 0x2a07, 0x2a0c, // 58-5f
|
||||
0x0029, 0x001e, 0x0030, 0x002e, 0x0020, 0x0012, 0x0021, 0x0022, // 60-67
|
||||
0x0023, 0x0017, 0x0024, 0x0025, 0x0026, 0x0032, 0x0031, 0x0018, // 68-6f
|
||||
0x0019, 0x0010, 0x0013, 0x001f, 0x0014, 0x0016, 0x002f, 0x0011, // 70-77
|
||||
0x002d, 0x0015, 0x002c, 0x2a1a, 0x0000, 0x2a1b, 0x2a29, 0x0000, // 78-7f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 80-87
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 88-8f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 90-97
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 98-9f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a0-a7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a8-af
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b0-b7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b8-bf
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c0-c7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c8-cf
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d0-d7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d8-df
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e0-e7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e8-ef
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // f0-f7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 // f8-ff
|
||||
};
|
||||
|
||||
static int keysyms_ff[] = {
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00-07
|
||||
0x000e, 0x000f, 0x0000, 0x004c, 0x0000, 0x001c, 0x0000, 0x0000, // 08-0f
|
||||
0x0000, 0x0000, 0x0000, 0xff45, 0x0000, 0x0000, 0x0000, 0x0000, // 10-17
|
||||
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, // 18-1f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 20-27
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 28-2f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 30-37
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 38-3f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 40-47
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 48-4f
|
||||
0x0047, 0x00cb, 0xaac8, 0x00cd, 0x00d0, 0x0049, 0x0051, 0x004f, // 50-57
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 58-5f
|
||||
0x0000, 0x0000, 0x0000, 0x0052, 0x0000, 0x0000, 0x0000, 0x00dd, // 60-67
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 68-6f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 70-77
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 78-7f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 80-87
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x009c, 0x0000, 0x0000, // 88-8f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 90-97
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 98-9f
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // a0-a7
|
||||
0x0000, 0x0000, 0x0037, 0x004e, 0x0000, 0x004a, 0x0000, 0x00b5, // a8-af
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // b0-b7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x003b, 0x003c, // b8-bf
|
||||
0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, // c0-c7
|
||||
0x0057, 0x0058, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // c8-cf
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d0-d7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // d8-df
|
||||
0x0000, 0x0036, 0x0000, 0x001d, 0x009d, 0x0000, 0x0000, 0x0000, // e0-e7
|
||||
0x0000, 0x0038, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // e8-ef
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // f0-f7
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0053 // f8-ff
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
vnc_kbdevent(rfbBool down, rfbKeySym k, rfbClientPtr cl)
|
||||
{
|
||||
int will_press = 0;
|
||||
int key;
|
||||
|
||||
#if 0
|
||||
pclog("VNC: kbdevent %d %x\n", down, k);
|
||||
#endif
|
||||
|
||||
if ((k >> 8) == 0x00) {
|
||||
will_press = keysyms_00[k & 0xff];
|
||||
} else if ((k >> 8) == 0xff) {
|
||||
will_press = keysyms_ff[k & 0xff];
|
||||
}
|
||||
|
||||
if (will_press <= 0) return;
|
||||
|
||||
#if 0
|
||||
pclog("VNC: translated to %x %x\n",
|
||||
(will_press >> 8) & 0xff, will_press & 0xff);
|
||||
#endif
|
||||
|
||||
/* First key. */
|
||||
key = (will_press >> 8) & 0xff;
|
||||
if (key > 0)
|
||||
recv_key[key] = down;
|
||||
|
||||
/* Second key. */
|
||||
key = will_press & 0xff;
|
||||
if (key > 0)
|
||||
recv_key[key] = down;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vnc_ptrevent(int but, int x, int y, rfbClientPtr cl)
|
||||
{
|
||||
if (x>=0 && x<allowedX && y>=0 && y<allowedY) {
|
||||
pclog("VNC: mouse event, x=%d, y=%d, buttons=%02x\n", x, y, but);
|
||||
|
||||
/* TODO: stuff a new "packet" into the platform mouse buffer. */
|
||||
}
|
||||
|
||||
rfbDefaultPtrAddEvent(but, x, y, cl);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vnc_clientgone(rfbClientPtr cl)
|
||||
{
|
||||
pclog("VNC: client disconnected: %s\n", cl->host);
|
||||
|
||||
if (clients > 0)
|
||||
clients--;
|
||||
if (clients == 0) {
|
||||
/* No more clients, pause the emulator. */
|
||||
pclog("VNC: no clients, pausing..\n");
|
||||
plat_pause(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static enum rfbNewClientAction
|
||||
vnc_newclient(rfbClientPtr cl)
|
||||
{
|
||||
/* Hook the ClientGone function so we know when they're gone. */
|
||||
cl->clientGoneHook = vnc_clientgone;
|
||||
|
||||
pclog("VNC: new client: %s\n", cl->host);
|
||||
if (++clients == 1) {
|
||||
/* We now have clients, un-pause the emulator if needed. */
|
||||
pclog("VNC: unpausing..\n");
|
||||
plat_pause(0);
|
||||
}
|
||||
|
||||
/* For now, we always accept clients. */
|
||||
return(RFB_CLIENT_ACCEPT);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vnc_display(rfbClientPtr cl)
|
||||
{
|
||||
/* Avoid race condition between resize and update. */
|
||||
if (!updatingSize && cl->newFBSizePending) {
|
||||
updatingSize = 1;
|
||||
} else if (updatingSize && !cl->newFBSizePending) {
|
||||
updatingSize = 0;
|
||||
|
||||
allowedX = rfb->width;
|
||||
allowedY = rfb->height;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vnc_blit(int x, int y, int y1, int y2, int w, int h)
|
||||
{
|
||||
uint32_t *p;
|
||||
int yy;
|
||||
|
||||
for (yy=y1; yy<y2; yy++) {
|
||||
p = (uint32_t *)&(((uint32_t *)rfb->frameBuffer)[yy*VNC_MAX_X]);
|
||||
|
||||
if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y)
|
||||
memcpy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w*4);
|
||||
}
|
||||
|
||||
video_blit_complete();
|
||||
|
||||
if (! updatingSize)
|
||||
rfbMarkRectAsModified(rfb, 0,0, allowedX,allowedY);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
vnc_blit8(int x, int y, int w, int h)
|
||||
{
|
||||
uint32_t *p;
|
||||
int xx, yy;
|
||||
|
||||
for (yy = 0; yy < h; yy++) {
|
||||
p = (uint32_t *)&(((uint32_t *)rfb->frameBuffer)[yy*VNC_MAX_X]);
|
||||
|
||||
if ((y+yy) >= 0 && (y+yy) < buffer->h) {
|
||||
for (xx=0; xx<w; xx++)
|
||||
p[xx] = pal_lookup[buffer->line[y+yy][x+xx]];
|
||||
}
|
||||
}
|
||||
|
||||
video_blit_complete();
|
||||
|
||||
if (! updatingSize)
|
||||
rfbMarkRectAsModified(rfb, 0,0, x+w,y+h);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize VNC for operation. */
|
||||
int
|
||||
vnc_init(UNUSED(void *arg))
|
||||
{
|
||||
static char title[128];
|
||||
rfbPixelFormat rpf = {
|
||||
/*
|
||||
* Screen format:
|
||||
* 32bpp; 32 depth;
|
||||
* little endian;
|
||||
* true color;
|
||||
* max 255 R/G/B;
|
||||
* red shift 16; green shift 8; blue shift 0;
|
||||
* padding
|
||||
*/
|
||||
32, 32, 0, 1, 255,255,255, 16, 8, 0, 0, 0
|
||||
};
|
||||
|
||||
if (rfb == NULL) {
|
||||
wcstombs(title, ui_window_title(NULL), sizeof(title));
|
||||
updatingSize = 0;
|
||||
allowedX = scrnsz_x;
|
||||
allowedY = scrnsz_y;
|
||||
|
||||
rfb = rfbGetScreen(0, NULL, VNC_MAX_X, VNC_MAX_Y, 8, 3, 4);
|
||||
rfb->desktopName = title;
|
||||
rfb->frameBuffer = (char *)malloc(VNC_MAX_X*VNC_MAX_Y*4);
|
||||
|
||||
rfb->serverFormat = rpf;
|
||||
rfb->alwaysShared = TRUE;
|
||||
rfb->displayHook = vnc_display;
|
||||
rfb->ptrAddEvent = vnc_ptrevent;
|
||||
rfb->kbdAddEvent = vnc_kbdevent;
|
||||
rfb->newClientHook = vnc_newclient;
|
||||
|
||||
/* Set up our current resolution. */
|
||||
rfb->width = allowedX;
|
||||
rfb->height = allowedY;
|
||||
|
||||
rfbInitServer(rfb);
|
||||
|
||||
rfbRunEventLoop(rfb, -1, TRUE);
|
||||
}
|
||||
|
||||
/* Set up our BLIT handlers. */
|
||||
video_setblit(vnc_blit8, vnc_blit);
|
||||
|
||||
clients = 0;
|
||||
|
||||
pclog("VNC: init complete.\n");
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vnc_close(void)
|
||||
{
|
||||
if (rfb != NULL) {
|
||||
free(rfb->frameBuffer);
|
||||
|
||||
rfbScreenCleanup(rfb);
|
||||
|
||||
rfb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vnc_resize(int x, int y)
|
||||
{
|
||||
rfbClientIteratorPtr iterator;
|
||||
rfbClientPtr cl;
|
||||
|
||||
if (rfb == NULL) return;
|
||||
|
||||
/* TightVNC doesn't like certain sizes.. */
|
||||
if (x < VNC_MIN_X || x > VNC_MAX_X || y < VNC_MIN_Y || y > VNC_MAX_Y) {
|
||||
pclog("VNC: invalid resoltion %dx%d requested!\n", x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((x != rfb->width || y != rfb->height) && x > 160 && y > 0) {
|
||||
pclog("VNC: updating resolution: %dx%d\n", x, y);
|
||||
|
||||
allowedX = (rfb->width < x) ? rfb->width : x;
|
||||
allowedY = (rfb->width < y) ? rfb->width : y;
|
||||
|
||||
rfb->width = x;
|
||||
rfb->height = y;
|
||||
|
||||
iterator = rfbGetClientIterator(rfb);
|
||||
while ((cl = rfbClientIteratorNext(iterator)) != NULL) {
|
||||
LOCK(cl->updateMutex);
|
||||
cl->newFBSizePending = 1;
|
||||
UNLOCK(cl->updateMutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Tell them to pause if we have no clients. */
|
||||
int
|
||||
vnc_pause(void)
|
||||
{
|
||||
return((clients > 0) ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vnc_take_screenshot(wchar_t *fn)
|
||||
{
|
||||
pclog("VNC: take_screenshot\n");
|
||||
}
|
||||
Reference in New Issue
Block a user