diff options
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r-- | x11vnc/x11vnc.c | 294 |
1 files changed, 205 insertions, 89 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index ef3faf4..bd06c44 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -405,7 +405,7 @@ int overlay_present = 0; #if LIBVNCSERVER_HAVE_LIBXRANDR #include <X11/extensions/Xrandr.h> #endif -static int xrandr_base_event_type = 0; +int xrandr_base_event_type = 0; int xfixes_present = 0; @@ -419,8 +419,8 @@ int alt_arrow = 1; #if LIBVNCSERVER_HAVE_LIBXFIXES #include <X11/extensions/Xfixes.h> -static int xfixes_base_event_type = 0; #endif +int xfixes_base_event_type = 0; int xdamage_present = 0; @@ -428,15 +428,15 @@ int use_xdamage = 1; /* just use the xdamage rects. for scanline hints */ #if LIBVNCSERVER_HAVE_LIBXDAMAGE #include <X11/extensions/Xdamage.h> Damage xdamage = 0; -static int xdamage_base_event_type = 0; #endif +int xdamage_base_event_type = 0; int xdamage_max_area = 20000; /* pixels */ double xdamage_memory = 1.0; /* in units of NSCAN */ int xdamage_tile_count; /* date +'lastmod: %Y-%m-%d' */ -char lastmod[] = "0.7.2pre lastmod: 2005-04-10"; +char lastmod[] = "0.7.2 lastmod: 2005-04-11"; int hack_val = 0; /* X display info */ @@ -559,7 +559,6 @@ unsigned char *tile_has_xdamage_diff, *tile_row_has_xdamage_diff; /* times of recent events */ time_t last_event, last_input, last_client = 0; -time_t last_sendevent = 0; /* last client to move pointer */ rfbClientPtr last_pointer_client = NULL; @@ -820,6 +819,8 @@ int pipeinput_tee = 0; unsigned long subwin = 0x0; /* -id, -sid */ int subwin_wait_mapped = 0; +int debug_xevents = 0; /* -R debug_xevents:1 */ + int xtrap_input = 0; /* -xtrap for user input insertion */ int xinerama = 0; /* -xinerama */ int xrandr = 0; /* -xrandr */ @@ -2315,20 +2316,23 @@ XImage *XCreateImage_wr(Display *disp, Visual *visual, unsigned int depth, void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) { char *src, *dst; int line, pixelsize = bpp/8; + int bpl = wdpy_x * pixelsize; + if (clipshift) { + x += coff_x; + y += coff_y; + } if (! raw_fb_seek) { - src = (raw_fb_addr + raw_fb_offset) - + raw_fb_image->bytes_per_line*y + pixelsize*x; + src = raw_fb_addr + raw_fb_offset + bpl*y + pixelsize*x; dst = dest->data; for (line = 0; line < h; line++) { memcpy(dst, src, w * pixelsize); - src += raw_fb_image->bytes_per_line; + src += bpl; dst += dest->bytes_per_line; } } else{ int n, len, del, sz = w * pixelsize; - int bpl = raw_fb_image->bytes_per_line; off_t off = (off_t) (raw_fb_offset + bpl*y + pixelsize*x); lseek(raw_fb_fd, off, SEEK_SET); @@ -2352,6 +2356,10 @@ void copy_raw_fb(XImage *dest, int x, int y, unsigned int w, unsigned int h) { } } } + if (bpl > sz) { + off = (off_t) (bpl - sz); + lseek(raw_fb_fd, off, SEEK_CUR); + } dst += dest->bytes_per_line; } } @@ -3187,6 +3195,25 @@ void set_client_input(char *str) { free(cl_list); } +void set_child_info(void) { + char pid[16]; + /* set up useful environment for child process */ + sprintf(pid, "%d", (int) getpid()); + set_env("X11VNC_PID", pid); + if (program_name) { + /* e.g. for remote control -R */ + set_env("X11VNC_PROG", program_name); + } + if (program_cmdline) { + set_env("X11VNC_CMDLINE", program_cmdline); + } + if (raw_fb_str) { + set_env("X11VNC_RAWFB_STR", raw_fb_str); + } else { + set_env("X11VNC_RAWFB_STR", ""); + } +} + /* * utility to run a user supplied command setting some RFB_ env vars. * used by, e.g., accept_client() and client_gone() @@ -6751,7 +6778,6 @@ int check_pipeinput(void) { void initialize_pipeinput(void) { char *p; - char pid[16]; if (pipeinput_fh != NULL) { rfbLog("closing pipeinput stream: %p\n", pipeinput_fh); @@ -6803,20 +6829,7 @@ void initialize_pipeinput(void) { p = pipeinput_str; } - /* set up useful environment for child process */ - sprintf(pid, "%d", (int) getpid()); - set_env("X11VNC_PID", pid); - if (program_name) { - /* e.g. for remote control -R */ - set_env("X11VNC_PROG", program_name); - } - if (program_cmdline) { - set_env("X11VNC_CMDLINE", program_cmdline); - } - if (raw_fb_str) { - set_env("X11VNC_RAWFB_STR", raw_fb_str); - } - + set_child_info(); rfbLog("pipeinput: starting: \"%s\"...\n", p); pipeinput_fh = popen(p, "w"); @@ -6862,7 +6875,7 @@ void initialize_pipeinput(void) { "# if two more more buttons change state in one event they are listed\n" "# separated by commas.\n" "#\n" -"# One might parse a Pointer like with:\n" +"# One might parse a Pointer line with:\n" "#\n" "# int client, x, y, mask; char *hint;\n" "# sscanf(line, \"Pointer %d %d %d %s\", &client, &x, &y, &mask, &hint);\n" @@ -6887,7 +6900,7 @@ void initialize_pipeinput(void) { "# You basically remove the leading 'XK_' prefix from the macro name in\n" "# that file to get the Keysym name.\n" "#\n" -"# One might parse a Pointer like with:\n" +"# One might parse a Keysym line with:\n" "#\n" "# int client, down, keysym; char *name, *hint;\n" "# sscanf(line, \"Keysym %d %d %s %s\", &client, &down, &keysym, &name, &hint);\n" @@ -6907,7 +6920,8 @@ void initialize_pipeinput(void) { "# info will be enough for most purposes (having identical keyboards on\n" "# both sides helps).\n" "#\n" -"# Here comes yours stream:\n" +"# Here comes your stream. The following token will always indicate the\n" +"# end of this informational text:\n" "# END_OF_TOP\n" ); fflush(pipeinput_fh); @@ -6921,10 +6935,9 @@ void initialize_pipeinput(void) { /* * Bell event handling. Requires XKEYBOARD extension. */ -#if LIBVNCSERVER_HAVE_XKEYBOARD - -static int xkb_base_event_type = 0; +int xkb_base_event_type = 0; +#if LIBVNCSERVER_HAVE_XKEYBOARD /* * check for XKEYBOARD, set up xkb_base_event_type */ @@ -7374,7 +7387,6 @@ static void selection_request(XEvent *ev) { if (! trapped_xerror) { XSendEvent(req_event->display, req_event->requestor, False, 0, (XEvent *)¬ify_event); - last_sendevent = time(0); } if (trapped_xerror) { rfbLog("selection_request: ignored XError while sending " @@ -7586,6 +7598,18 @@ void initialize_xevents(void) { } } +void print_xevent_bases(void) { + fprintf(stderr, "X event bases: xkb=%d, xtest=%d, xrandr=%d, " + "xfixes=%d, xdamage=%d, xtrap=%d\n", xkb_base_event_type, + xtest_base_event_type, xrandr_base_event_type, + xfixes_base_event_type, xdamage_base_event_type, + xtrap_base_event_type); + fprintf(stderr, " MapNotify=%d, ClientMsg=%d PropNotify=%d " + "SelNotify=%d, SelRequest=%d\n", MappingNotify, ClientMessage, + PropertyNotify, SelectionNotify, SelectionRequest); + fprintf(stderr, " SelClear=%d, Expose=%d\n", SelectionClear, Expose); +} + /* * This routine is periodically called to check for selection related * and other X11 events and respond to them as needed. @@ -7685,9 +7709,6 @@ void check_xevents(void) { ; } } - } - - if (last_sendevent && (now > last_sendevent+1 || now % 10 == 0)) { /* * we can get ClientMessage from our XSendEvent() call in * selection_request(). @@ -7695,7 +7716,6 @@ void check_xevents(void) { while (XCheckTypedEvent(dpy, ClientMessage, &xev)) { ; } - last_sendevent = 0; } /* check for CUT_BUFFER0 and VNC_CONNECT changes: */ @@ -7804,28 +7824,44 @@ void check_xevents(void) { #define DEBUG_XEVENTS 1 #endif #if DEBUG_XEVENTS - if (hack_val) { + if (debug_xevents) { static time_t last_check = 0; + static time_t reminder = 0; + static int freq = 0; + + if (! freq) { + if (getenv("X11VNC_REMINDER_RATE")) { + freq = atoi(getenv("X11VNC_REMINDER_RATE")); + } else { + freq = 300; + } + } if (now > last_check + 1) { + int ev_max = 300, ev_size = 400; XEvent xevs[400]; int i, tot = XEventsQueued(dpy, QueuedAlready); + if (reminder == 0 || (tot && now > reminder + freq)) { + print_xevent_bases(); + reminder = now; + } last_check = now; + if (tot) { fprintf(stderr, "Total events queued: %d\n", tot); } - for (i=1; i<300; i++) { + for (i=1; i<ev_max; i++) { int k, n = 0; while (XCheckTypedEvent(dpy, i, xevs+n)) { - if (++n >= 400) { + if (++n >= ev_size) { break; } } if (n) { - fprintf(stderr, "%d events of type %d " - "queued\n", n, i); + fprintf(stderr, " %d events of type %d" + " queued\n", n, i); } for (k=n-1; k >= 0; k--) { XPutBackEvent(dpy, xevs+k); @@ -7843,6 +7879,8 @@ void check_xevents(void) { if (qlen >= bugout) { rfbLog("event leak: %d queued, " " calling XSync(dpy, True)\n", qlen); + rfbLog(" for diagnostics run: 'x11vnc -R" + " debug_xevents:1'\n"); XSync(dpy, True); } } @@ -10344,6 +10382,11 @@ char *process_remote_cmd(char *cmd, int stringonly) { p += strlen("rawfb:"); if (raw_fb_str) free(raw_fb_str); raw_fb_str = strdup(p); + if (safe_remote_only && strstr(p, "setup:") == p) { + /* n.b. we still allow filename, shm, of rawfb */ + fprintf(stderr, "unsafe rawfb setup: %s\n", p); + exit(1); + } rfbLog("process_remote_cmd: setting -rawfb to:\n" "\t'%s'\n", p); @@ -10538,6 +10581,16 @@ char *process_remote_cmd(char *cmd, int stringonly) { rfbLog("process_remote_cmd: disabling remote commands.\n"); accept_remote_cmds = 0; /* cannot be turned back on. */ + } else if (strstr(p, "debug_xevents:") == p) { + COLON_CHECK("debug_xevents:") + if (query) { + snprintf(buf, bufn, "ans=%s%s%d", p, co, debug_xevents); + goto qry; + } + p += strlen("debug_xevents:"); + debug_xevents = atoi(p); + rfbLog("set debug_xevents to: %d\n", debug_xevents); + } else if (strstr(p, "hack:") == p) { /* skip-cmd-list */ COLON_CHECK("hack:") if (query) { @@ -10640,6 +10693,9 @@ char *process_remote_cmd(char *cmd, int stringonly) { snprintf(buf, bufn, "aro=%s:%s", p, NONUL(sigpipe)); } else if (!strcmp(p, "threads")) { snprintf(buf, bufn, "aro=%s:%d", p, use_threads); + } else if (!strcmp(p, "pipeinput")) { + snprintf(buf, bufn, "aro=%s:%s", p, + NONUL(pipeinput_str)); } else if (!strcmp(p, "clients")) { char *str = list_clients(); snprintf(buf, bufn, "aro=%s:%s", p, str); @@ -11064,7 +11120,7 @@ void check_xdamage_state(void) { * Create or destroy the Damage object as needed, we don't want * one if no clients are connected. */ - if (client_count) { + if (client_count && use_xdamage) { create_xdamage_if_needed(); } else { destroy_xdamage_if_needed(); @@ -13391,7 +13447,7 @@ XImage *initialize_raw_fb(void) { int w, h, b, shmid = 0; unsigned long rm = 0, gm = 0, bm = 0; static XImage ximage_struct; /* n.b.: not (XImage *) */ - int closedpy = 1; + int closedpy = 1, i, m; if (raw_fb_addr || raw_fb_seek) { if (raw_fb_shm) { @@ -13415,7 +13471,38 @@ XImage *initialize_raw_fb(void) { } - str = strdup(raw_fb_str); + if ( (q = strstr(raw_fb_str, "setup:")) == raw_fb_str) { + FILE *pipe; + char line[1024], *t; + + set_child_info(); + q += strlen("setup:"); + rfbLog("running command to setup rawfb: %s\n", q); + pipe = popen(q, "r"); + if (! pipe) { + rfbLog("popen of setup command failed.\n"); + rfbLogPerror("popen"); + clean_up_exit(1); + } + line[0] = '\0'; + if (fgets(line, 1024, pipe) == NULL) { + rfbLog("read of setup command failed.\n"); + clean_up_exit(1); + } + pclose(pipe); + str = strdup(line); + t = str; + while (*t != '\0') { + if (*t == '\n') { + *t = '\0'; + } + t++; + } + rfbLog("setup command returned: %s\n", str); + + } else { + str = strdup(raw_fb_str); + } /* * uppercase means do not close the display (e.g. for remote control) @@ -13480,12 +13567,12 @@ XImage *initialize_raw_fb(void) { } } if ((q = strrchr(str, '@')) == NULL) { - rfbLog("invalid rawfb str: %s\n", raw_fb_str); + rfbLog("invalid rawfb str: %s\n", str); clean_up_exit(1); } /* @WxHxB */ if (sscanf(q, "@%dx%dx%d", &w, &h, &b) != 3) { - rfbLog("invalid rawfb str: %s\n", raw_fb_str); + rfbLog("invalid rawfb str: %s\n", str); clean_up_exit(1); } @@ -13505,8 +13592,7 @@ XImage *initialize_raw_fb(void) { /* shm:N */ raw_fb_addr = (char *) shmat(shmid, 0, SHM_RDONLY); if (! raw_fb_addr) { - rfbLog("failed to attach to shm: %d, %s\n", shmid, - raw_fb_str); + rfbLog("failed to attach to shm: %d, %s\n", shmid, str); rfbLogPerror("shmat"); clean_up_exit(1); } @@ -13528,7 +13614,7 @@ XImage *initialize_raw_fb(void) { fd = open(q, O_RDONLY); if (fd < 0) { - rfbLog("failed to open file: %s, %s\n", q, raw_fb_str); + rfbLog("failed to open file: %s, %s\n", q, str); rfbLogPerror("open"); clean_up_exit(1); } @@ -13549,8 +13635,7 @@ XImage *initialize_raw_fb(void) { fd, 0); if (raw_fb_addr == MAP_FAILED || raw_fb_addr == NULL) { - rfbLog("failed to mmap file: %s, %s\n", - q, raw_fb_str); + rfbLog("failed to mmap file: %s, %s\n", q, str); rfbLog(" raw_fb_addr: %p\n", raw_fb_addr); rfbLogPerror("mmap"); clean_up_exit(1); @@ -13572,7 +13657,7 @@ XImage *initialize_raw_fb(void) { rfbLog(" W: %d H: %d B: %d sz: %d\n", w, h, b, size); } } else { - rfbLog("invalid rawfb str: %s\n", raw_fb_str); + rfbLog("invalid rawfb str: %s\n", str); clean_up_exit(1); } @@ -13580,14 +13665,15 @@ XImage *initialize_raw_fb(void) { raw_fb_image = &ximage_struct; } - raw_fb = (char *) malloc(w*h*b/8); + initialize_clipshift(); + + raw_fb = (char *) malloc(dpy_x * dpy_y * b/8); raw_fb_image->data = raw_fb; raw_fb_image->format = ZPixmap; - raw_fb_image->width = w; - raw_fb_image->height = h; + raw_fb_image->width = dpy_x; + raw_fb_image->height = dpy_y; raw_fb_image->bits_per_pixel = b; - raw_fb_image->depth = (b == 32) ? 24 : b; - raw_fb_image->bytes_per_line = w*b/8; + raw_fb_image->bytes_per_line = dpy_x*b/8; if (rm == 0 && gm == 0 && bm == 0) { /* guess masks... */ @@ -13610,18 +13696,36 @@ XImage *initialize_raw_fb(void) { raw_fb_image->green_mask = gm; raw_fb_image->blue_mask = bm; - if (raw_fb_addr) { - memcpy(raw_fb, raw_fb_addr + raw_fb_offset, w*h*(b/8)); + raw_fb_image->depth = 0; + m = 1; + for (i=0; i<32; i++) { + if (rm & m) { + raw_fb_image->depth++; + } + if (gm & m) { + raw_fb_image->depth++; + } + if (bm & m) { + raw_fb_image->depth++; + } + m = m << 1; + } + if (! raw_fb_image->depth) { + raw_fb_image->depth = (b == 32) ? 24 : b; + } + + if (clipshift) { + memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); + } else if (raw_fb_addr) { + memcpy(raw_fb, raw_fb_addr + raw_fb_offset, dpy_x*dpy_y*b/8); } else { - memset(raw_fb, 0xff, w*h*(b/8)); + memset(raw_fb, 0xff, dpy_x * dpy_y * b/8); } rfbLog("rawfb: raw_fb %p\n", raw_fb); free(str); - initialize_clipshift(); - return raw_fb_image; } @@ -16614,7 +16718,7 @@ void mark_rect_as_modified(int x1, int y1, int x2, int y2, int force) { if (damage_time != 0) { /* * This is not XDAMAGE, rather a hack for testing - * were we allow the framebuffer to be corrupted for + * where we allow the framebuffer to be corrupted for * damage_delay seconds. */ int debug = 0; @@ -20204,12 +20308,18 @@ static void print_help(int mode) { "-rawfb string Experimental option, instead of polling X, poll the\n" " memory object specified in \"string\". For shared\n" " memory segments it is of the form: \"shm:N@WxHxB\"\n" -" which specifies a shmid N and framebuffer width, height,\n" -" and bits per pixel. To memory map mmap(2) a file use:\n" +" which specifies a shmid N and framebuffer Width, Height,\n" +" and Bits per pixel. To memory map mmap(2) a file use:\n" " \"map:/path/to/a/file@WxHxB\". If there is trouble\n" " with mmap, use \"file:/...\" for slower lseek(2) based\n" " reading.\n" "\n" +" If string is \"setup:cmd\", then the command \"cmd\"\n" +" is run and the first line from it is read and used\n" +" as \"string\". This allows initializing the device,\n" +" determining WxHxB, etc. These are often done as root\n" +" so take care.\n" +"\n" " Optional suffixes are \":R/G/B\" and \"+O\" to specify\n" " red, green, and blue masks and an offset into the\n" " memory object. If the masks are not provided x11vnc\n" @@ -20229,17 +20339,18 @@ static void print_help(int mode) { " before setting/changing them. If you don't want x11vnc\n" " to close the DISPLAY in rawfb mode, then capitalize\n" " the prefix, SHM:, MAP: etc. Keeping the display open\n" -" enables defautl remote control channel.\n" +" enables default remote-control channel.\n" "\n" -"-pipeinput cmd Another experimental option: it lets you supply an\n" -" extern command in \"cmd\" that x11vnc will pipe all of\n" -" the user input events to in a simple format. By default\n" -" x11vnc will not process any of the user input events.\n" -" If you prefix \"cmd\" with \"tee:\" it will both send\n" -" them to the pipe command and process them. For a\n" -" description of the format run \"-pipeinput tee:cat\".\n" -" Another prefix is \"reopen\" which means to reopen pipe\n" -" if it exits. Separate multiple prefixes with commas.\n" +"-pipeinput cmd Another experimental option: it lets you supply\n" +" an extern command in \"cmd\" that x11vnc will pipe\n" +" all of the user input events to in a simple format.\n" +" In -pipeinput mode by default x11vnc will not process\n" +" any of the user input events. If you prefix \"cmd\"\n" +" with \"tee:\" it will both send them to the pipe\n" +" command and process them. For a description of the\n" +" format run \"-pipeinput tee:/bin/cat\". Another prefix\n" +" is \"reopen\" which means to reopen pipe if it exits.\n" +" Separate multiple prefixes with commas.\n" "\n" " In combination with -rawfb one might be able to\n" " do amusing things (e.g. control non-X devices).\n" @@ -20588,25 +20699,26 @@ static void print_help(int mode) { " noxwarp noxwarppointer buttonmap dragging nodragging\n" " pointer_mode pm input_skip input client_input speeds\n" " debug_pointer dp nodebug_pointer nodp debug_keyboard dk\n" -" nodebug_keyboard nodk deferupdate defer wait rfbwait\n" -" nap nonap sb screen_blank fs gaps grow fuzz snapfb\n" -" nosnapfb rawfb progressive rfbport http nohttp httpport\n" +" nodebug_keyboard nodk deferupdate defer wait rfbwait nap\n" +" nonap sb screen_blank fs gaps grow fuzz snapfb nosnapfb\n" +" rawfb setup: progressive rfbport http nohttp httpport\n" " httpdir enablehttpproxy noenablehttpproxy alwaysshared\n" " noalwaysshared nevershared noalwaysshared dontdisconnect\n" " nodontdisconnect desktop noremote\n" "\n" -" aro= display vncdisplay desktopname http_url auth\n" -" users rootshift clipshift scale_str scaled_x scaled_y\n" -" scale_numer scale_denom scale_fac scaling_blend\n" -" scaling_nomult4 scaling_pad scaling_interpolate\n" -" inetd safer unsafe passwdfile using_shm logfile o\n" -" flag rc norc h help V version lastmod bg sigpipe\n" -" threads clients client_count pid ext_xtest ext_xtrap\n" -" ext_xkb ext_xshm ext_xinerama ext_overlay ext_xfixes\n" -" ext_xdamage ext_xrandr rootwin num_buttons button_mask\n" -" mouse_x mouse_y bpp depth indexed_color dpy_x dpy_y\n" -" wdpy_x wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y\n" -" rfbauth passwd\n" +" aro= debug_xevents: display vncdisplay desktopname\n" +" http_url auth users rootshift clipshift scale_str\n" +" scaled_x scaled_y scale_numer scale_denom\n" +" scale_fac scaling_blend scaling_nomult4 scaling_pad\n" +" scaling_interpolate inetd safer unsafe passwdfile\n" +" using_shm logfile o flag rc norc h help V version\n" +" lastmod bg sigpipe threads pipeinput clients\n" +" client_count pid ext_xtest ext_xtrap ext_xkb ext_xshm\n" +" ext_xinerama ext_overlay ext_xfixes ext_xdamage\n" +" ext_xrandr rootwin num_buttons button_mask mouse_x\n" +" mouse_y bpp depth indexed_color dpy_x dpy_y wdpy_x\n" +" wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth\n" +" passwd\n" "\n" "-sync By default -remote commands are run asynchronously, that\n" " is, the request is posted and the program immediately\n" @@ -22215,6 +22327,10 @@ int main(int argc, char* argv[]) { } else { xtest_present = 1; xtest_base_event_type = ev; + if (maj <= 1 || (maj == 2 && min <= 2)) { + /* no events defined as of 2.2 */ + xtest_base_event_type = 0; + } } if (! XETrapQueryExtension_wr(dpy, &ev, &er, &maj)) { |