summaryrefslogtreecommitdiffstats
path: root/x11vnc/screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/screen.c')
-rw-r--r--x11vnc/screen.c328
1 files changed, 326 insertions, 2 deletions
diff --git a/x11vnc/screen.c b/x11vnc/screen.c
index 264b9c4..44b7b98 100644
--- a/x11vnc/screen.c
+++ b/x11vnc/screen.c
@@ -24,6 +24,8 @@
#include "macosx.h"
#include "macosxCG.h"
+#include <rfb/rfbclient.h>
+
void set_greyscale_colormap(void);
void set_hi240_colormap(void);
void unset_colormap(void);
@@ -43,6 +45,11 @@ void initialize_screen(int *argc, char **argv, XImage *fb);
void set_vnc_desktop_name(void);
void announce(int lport, int ssl, char *iface);
+char *vnc_reflect_guess(char *str, char **raw_fb_addr);
+void vnc_reflect_process_client(void);
+rfbBool vnc_reflect_send_pointer(int x, int y, int mask);
+rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down);
+rfbBool vnc_reflect_send_cuttext(char *str, int len);
static void debug_colormap(XImage *fb);
static void set_visual(char *str);
@@ -57,6 +64,7 @@ static void setup_scaling(int *width_in, int *height_in);
int rawfb_reset = -1;
int rawfb_dev_video = 0;
+int rawfb_vnc_reflect = 0;
/*
* X11 and rfb display/screen related routines
@@ -605,7 +613,9 @@ void set_raw_fb_params(int restore) {
view_only = 1;
}
#endif
- if (watch_selection) {
+ if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) {
+ ;
+ } else if (watch_selection) {
if (verbose) rfbLog(" rawfb: turning off "
"watch_selection\n");
watch_selection = 0;
@@ -635,7 +645,11 @@ void set_raw_fb_params(int restore) {
use_solid_bg = 0;
}
#ifndef MACOSX
- multiple_cursors_mode = strdup("arrow");
+ if (raw_fb_str && strstr(raw_fb_str, "vnc") == raw_fb_str) {
+ ;
+ } else {
+ multiple_cursors_mode = strdup("arrow");
+ }
#endif
}
if (using_shm) {
@@ -830,6 +844,281 @@ static void initialize_snap_fb(void) {
snap_fb = snap->data;
}
+rfbClient* client = NULL;
+
+void vnc_reflect_bell(rfbClient *cl) {
+ if (sound_bell) {
+ if (unixpw_in_progress) {
+ return;
+ }
+ if (! all_clients_initialized()) {
+ rfbLog("vnc_reflect_bell: not sending bell: "
+ "uninitialized clients\n");
+ } else {
+ if (screen && client_count) {
+ rfbSendBell(screen);
+ }
+ }
+ }
+}
+
+void vnc_reflect_recv_cuttext(rfbClient *cl, const char *str, int len) {
+ if (unixpw_in_progress) {
+ return;
+ }
+ if (! watch_selection) {
+ return;
+ }
+ if (! all_clients_initialized()) {
+ rfbLog("vnc_reflect_recv_cuttext: no send: uninitialized clients\n");
+ return; /* some clients initializing, cannot send */
+ }
+ rfbSendServerCutText(screen, (char *)str, len);
+}
+
+void vnc_reflect_got_update(rfbClient *cl, int x, int y, int w, int h) {
+ if (use_xdamage) {
+ static int first = 1;
+ if (first) {
+ collect_non_X_xdamage(-1, -1, -1, -1, 0);
+ first = 0;
+ }
+ collect_non_X_xdamage(x, y, w, h, 1);
+ }
+}
+
+void vnc_reflect_got_cursorshape(rfbClient *cl, int xhot, int yhot, int width, int height, int bytesPerPixel) {
+ static int serial = 1;
+ int i, j;
+ char *bitmap, *rich, *alpha;
+ char *pixels = NULL;
+ unsigned long r, g, b, a;
+ unsigned int ui;
+ unsigned long red_mask, green_mask, blue_mask;
+
+ if (unixpw_in_progress) {
+ return;
+ }
+ if (! all_clients_initialized()) {
+ rfbLog("vnc_reflect_got_copyshape: no send: uninitialized clients\n");
+ return; /* some clients initializing, cannot send */
+ }
+ if (! client->rcSource) {
+ return;
+ }
+ if (bytesPerPixel != 1 && bytesPerPixel != 2 && bytesPerPixel != 4) {
+ return;
+ }
+
+ red_mask = (client->format.redMax << client->format.redShift);
+ green_mask = (client->format.greenMax << client->format.greenShift);
+ blue_mask = (client->format.blueMax << client->format.blueShift);
+
+ pixels = (char *)malloc(4*width*height);
+ for (j=0; j<height; j++) {
+ for (i=0; i<width; i++) {
+ unsigned int* uip;
+ unsigned char* uic;
+ int m;
+ if (bytesPerPixel == 1) {
+ unsigned char* p = (unsigned char *) client->rcSource;
+ ui = (unsigned long) *(p + j * width + i);
+ } else if (bytesPerPixel == 2) {
+ unsigned short* p = (unsigned short *) client->rcSource;
+ ui = (unsigned long) *(p + j * width + i);
+ } else if (bytesPerPixel == 4) {
+ unsigned int* p = (unsigned int *) client->rcSource;
+ ui = (unsigned long) *(p + j * width + i);
+ }
+ r = (red_mask & ui) >> client->format.redShift;
+ g = (green_mask & ui) >> client->format.greenShift;
+ b = (blue_mask & ui) >> client->format.blueShift;
+
+ r = (255 * r) / client->format.redMax;
+ g = (255 * g) / client->format.greenMax;
+ b = (255 * b) / client->format.blueMax;
+
+ ui = (r << 16 | g << 8 | b << 0) ;
+
+ uic = (unsigned char *)client->rcMask;
+ m = (int) *(uic + j * width + i);
+ if (m) {
+ ui |= 0xff000000;
+ }
+ uip = (unsigned int *)pixels;
+ *(uip + j * width + i) = ui;
+ }
+ }
+
+ store_cursor(serial++, (unsigned long*) pixels, width, height, 32, xhot, yhot);
+ free(pixels);
+ set_cursor(cursor_x, cursor_y, get_which_cursor());
+}
+
+void vnc_reflect_got_copyrect(rfbClient *cl, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
+ sraRegionPtr reg;
+ int dx, dy, rc = -1;
+ static int last_dx = 0, last_dy = 0;
+ if (unixpw_in_progress) {
+ return;
+ }
+ if (! all_clients_initialized()) {
+ rfbLog("vnc_reflect_got_copyrect: no send: uninitialized clients\n");
+ return; /* some clients initializing, cannot send */
+ }
+ dx = dest_x - src_x;
+ dy = dest_y - src_y;
+ if (dx != last_dx || dy != last_dy) {
+ rc = fb_push_wait(0.05, FB_COPY|FB_MOD);
+ }
+ if (0) fprintf(stderr, "vnc_reflect_got_copyrect: %dx%d+%d+%d %d %d rc=%d\n", dest_x, dest_y, w, h, dx, dy, rc);
+ reg = sraRgnCreateRect(dest_x, dest_y, dest_x + w, dest_y + h);
+ do_copyregion(reg, dx, dy, 0);
+ sraRgnDestroy(reg);
+
+ last_dx = dx;
+ last_dy = dy;
+}
+
+rfbBool vnc_reflect_resize(rfbClient *cl) {
+ static int first = 1;
+ if(cl->frameBuffer) {
+ free(cl->frameBuffer);
+ }
+ cl->frameBuffer= malloc(cl->width * cl->height * cl->format.bitsPerPixel/8);
+ if (!first) {
+ do_new_fb(1);
+ }
+ first = 0;
+ return cl->frameBuffer ? TRUE : FALSE;
+}
+
+char *vnc_reflect_guess(char *str, char **raw_fb_addr) {
+
+ static int first = 1;
+ char *hp = str + strlen("vnc:");
+ char *at = NULL;
+ int argc = 0, i;
+ char *argv[16];
+ char str2[256];
+ char *str0 = strdup(str);
+
+ if (client == NULL) {
+ client = rfbGetClient(8, 3, 4);
+ }
+
+ rfbLog("rawfb: %s\n", str);
+
+ at = strchr(hp, '@');
+ if (at) {
+ *at = '\0';
+ at++;
+ }
+
+ client->appData.useRemoteCursor = TRUE;
+ client->Bell = vnc_reflect_bell;
+ client->GotXCutText = vnc_reflect_recv_cuttext;
+ client->GotCopyRect = vnc_reflect_got_copyrect;
+ client->GotCursorShape = vnc_reflect_got_cursorshape;
+ client->MallocFrameBuffer = vnc_reflect_resize;
+ client->canHandleNewFBSize = TRUE;
+ client->GotFrameBufferUpdate = vnc_reflect_got_update;
+
+ if (first) {
+ argv[argc++] = "x11vnc_rawfb_vnc";
+ if (strstr(hp, "listen") == hp) {
+ char *q = strchr(hp, ':');
+ argv[argc++] = strdup("-listen");
+ if (q) {
+ client->listenPort = atoi(q+1);
+ } else {
+ client->listenPort = LISTEN_PORT_OFFSET;
+ }
+ } else {
+ argv[argc++] = strdup(hp);
+ }
+
+ if (! rfbInitClient(client, &argc, argv)) {
+ rfbLog("vnc_reflector failed for: %s\n", str0);
+ clean_up_exit(1);
+ }
+ }
+
+ if (at) {
+ sprintf(str2, "map:/dev/null@%s", at);
+ } else {
+ unsigned long red_mask, green_mask, blue_mask;
+ red_mask = (client->format.redMax << client->format.redShift);
+ green_mask = (client->format.greenMax << client->format.greenShift);
+ blue_mask = (client->format.blueMax << client->format.blueShift);
+ sprintf(str2, "map:/dev/null@%dx%dx%d:0x%x/0x%x/0x%x",
+ client->width, client->height, client->format.bitsPerPixel,
+ red_mask, green_mask, blue_mask);
+ }
+ *raw_fb_addr = client->frameBuffer;
+ free(str0);
+
+ if (first) {
+ setup_cursors_and_push();
+
+ for (i=0; i<10; i++) {
+ vnc_reflect_process_client();
+ }
+ }
+ first = 0;
+
+ return strdup(str2);
+}
+
+rfbBool vnc_reflect_send_pointer(int x, int y, int mask) {
+ rfbBool ret;
+ int rc;
+ if (mask >= 0) {
+ got_user_input++;
+ got_pointer_input++;
+ last_pointer_time = time(NULL);
+ }
+
+ if (cursor_x != x || cursor_y != y) {
+ last_pointer_motion_time = dnow();
+ }
+
+ cursor_x = x;
+ cursor_y = y;
+
+ /* record the x, y position for the rfb screen as well. */
+ cursor_position(x, y);
+
+ /* change the cursor shape if necessary */
+ rc = set_cursor(x, y, get_which_cursor());
+ cursor_changes += rc;
+
+ return SendPointerEvent(client, x, y, mask);
+}
+
+rfbBool vnc_reflect_send_key(uint32_t key, rfbBool down) {
+ return SendKeyEvent(client, key, down);
+}
+
+rfbBool vnc_reflect_send_cuttext(char *str, int len) {
+ return SendClientCutText(client, str, len);
+}
+
+void vnc_reflect_process_client(void) {
+ int num;
+ rfbBool save;
+ if (client == NULL) {
+ return;
+ }
+ num = WaitForMessage(client, 1000);
+ if (num > 0) {
+ if (!HandleRFBServerMessage(client)) {
+ rfbLog("vnc_reflect_process_client: read failure to server\n");
+ shut_down = 1;
+ }
+ }
+}
+
#define RAWFB_MMAP 1
#define RAWFB_FILE 2
#define RAWFB_SHM 3
@@ -842,6 +1131,7 @@ XImage *initialize_raw_fb(int reset) {
static XImage ximage_struct_snap;
int closedpy = 1, i, m, db = 0;
int do_macosx = 0;
+ int do_reflect = 0;
static char *last_file = NULL;
static int last_mode = 0;
@@ -988,6 +1278,7 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
raw_fb_addr = NULL;
raw_fb_offset = 0;
raw_fb_bytes_per_line = 0;
+ rawfb_vnc_reflect = 0;
last_mode = 0;
if (last_file) {
@@ -1023,6 +1314,18 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
}
str = str2;
rfbLog("console_guess returned: %s\n", str);
+ } else if (strstr(str, "vnc:") == str) {
+ char *str2 = vnc_reflect_guess(str, &raw_fb_addr);
+
+ rawfb_vnc_reflect = 1;
+ do_reflect = 1;
+
+ str = str2;
+ rfbLog("vnc_reflector set rawfb str to: %s\n", str);
+ if (pipeinput_str == NULL) {
+ pipeinput_str = strdup("VNC");
+ }
+ initialize_pipeinput();
}
if (closedpy && !view_only && got_noviewonly) {
@@ -1222,6 +1525,12 @@ if (db) fprintf(stderr, "initialize_raw_fb reset\n");
rfbLog(" w: %d h: %d b: %d addr: %p sz: %d\n", w, h,
b, raw_fb_addr, size);
last_mode = 0;
+ } else if (do_reflect) {
+ raw_fb_mmap = size;
+ rfbLog("rawfb: vnc fb: %s\n", q);
+ rfbLog(" w: %d h: %d b: %d addr: %p sz: %d\n", w, h,
+ b, raw_fb_addr, size);
+ last_mode = 0;
} else if (do_mmap) {
#if LIBVNCSERVER_HAVE_MMAP
@@ -1987,6 +2296,20 @@ static void setup_rotating(void) {
}
}
+static rfbBool set_xlate_wrapper(rfbClientPtr cl) {
+ static int first = 1;
+ if (first) {
+ first = 0;
+ } else if (ncache) {
+ int save = ncache_xrootpmap;
+ rfbLog("set_xlate_wrapper: clearing -ncache for new pixel format.\n");
+ ncache_xrootpmap = 0;
+ check_ncache(1, 0);
+ ncache_xrootpmap = save;
+ }
+ return rfbSetTranslateFunction(cl);
+}
+
/*
* initialize the rfb framebuffer/screen
*/
@@ -2507,6 +2830,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
screen->kbdAddEvent = keyboard;
screen->ptrAddEvent = pointer;
screen->setXCutText = xcut_receive;
+ screen->setTranslateFunction = set_xlate_wrapper;
/* called from inetd, we need to treat stdio as our socket */
if (inetd && use_openssl) {
OpenPOWER on IntegriCloud