summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c500
1 files changed, 476 insertions, 24 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index a5d34a8..fbf896a 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -273,7 +273,7 @@ static int xdamage_base_event_type;
#endif
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.7.1pre lastmod: 2005-01-23";
+char lastmod[] = "0.7.1pre lastmod: 2005-02-05";
/* X display info */
@@ -402,6 +402,7 @@ void close_clients(char *);
void autorepeat(int restore);
char *bitprint(unsigned int, int);
void blackout_tiles(void);
+void solid_bg(int);
void check_connect_inputs(void);
void check_padded_fb(void);
void clean_up_exit(int);
@@ -526,6 +527,9 @@ char *logfile = NULL;
int logfile_append = 0;
char *passwdfile = NULL;
char *blackout_str = NULL;
+int use_solid_bg = 0;
+char *solid_str = NULL;
+char *solid_default = "cyan4";
char *speeds_str = NULL;
int measure_speeds = 1;
@@ -1340,6 +1344,9 @@ void clean_up_exit (int ret) {
if (no_autorepeat) {
autorepeat(1);
}
+ if (use_solid_bg) {
+ solid_bg(1);
+ }
X_LOCK;
XTestDiscard_wr(dpy);
XCloseDisplay(dpy);
@@ -1390,6 +1397,9 @@ static void interrupted (int sig) {
if (no_autorepeat) {
autorepeat(1);
}
+ if (use_solid_bg) {
+ solid_bg(1);
+ }
if (sig) {
exit(2);
@@ -1803,6 +1813,9 @@ static void client_gone(rfbClientPtr client) {
if (no_autorepeat && client_count == 0) {
autorepeat(1);
}
+ if (use_solid_bg && client_count == 0) {
+ solid_bg(1);
+ }
if (gone_cmd && *gone_cmd != '\0') {
rfbLog("client_gone: using cmd for: %s\n", client->host);
run_user_command(gone_cmd, client, "gone");
@@ -2830,6 +2843,9 @@ enum rfbNewClientAction new_client(rfbClientPtr client) {
/* first client, turn off X server autorepeat */
autorepeat(0);
}
+ if (use_solid_bg && client_count == 1) {
+ solid_bg(0);
+ }
if (pad_geometry) {
install_padded_fb(pad_geometry);
@@ -6740,6 +6756,62 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
single_copytile = 0;
+ } else if (strstr(p, "solid_color") == p) {
+ char *new;
+ int doit = 1;
+ COLON_CHECK("solid_color:")
+ if (query) {
+ snprintf(buf, bufn, "ans=%s%s%s", p, co,
+ NONUL(solid_str));
+ goto qry;
+ }
+ p += strlen("solid_color:");
+ if (*p != '\0') {
+ new = strdup(p);
+ } else {
+ new = strdup(solid_default);
+ }
+ rfbLog("process_remote_cmd: solid %s -> %s\n",
+ NONUL(solid_str), new);
+
+ if (solid_str) {
+ if (!strcmp(solid_str, new)) {
+ doit = 0;
+ }
+ free(solid_str);
+ }
+ solid_str = new;
+ use_solid_bg = 1;
+
+ if (doit && client_count) {
+ solid_bg(0);
+ }
+ } else if (!strcmp(p, "solid")) {
+ int orig = use_solid_bg;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, use_solid_bg);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: enable -solid mode\n");
+ if (! solid_str) {
+ solid_str = strdup(solid_default);
+ }
+ use_solid_bg = 1;
+ if (client_count && !orig) {
+ solid_bg(0);
+ }
+ } else if (!strcmp(p, "nosolid")) {
+ int orig = use_solid_bg;
+ if (query) {
+ snprintf(buf, bufn, "ans=%s:%d", p, !use_solid_bg);
+ goto qry;
+ }
+ rfbLog("process_remote_cmd: disable -solid mode\n");
+ use_solid_bg = 0;
+ if (client_count && orig) {
+ solid_bg(1);
+ }
+
} else if (strstr(p, "blackout") == p) {
char *before, *old;
COLON_CHECK("blackout:")
@@ -10581,6 +10653,325 @@ void initialize_screen(int *argc, char **argv, XImage *fb) {
}
}
+/* -- solid.c -- */
+
+int do_cmd(char *cmd) {
+ int rc;
+ if (!cmd || *cmd == '\0') {
+ return 0;
+ }
+ rfbLog("running command:\n %s\n", cmd);
+ rc = system(cmd);
+ if (rc >= 256) {
+ rc = rc/256;
+ }
+ return rc;
+}
+
+char *cmd_output(char *cmd) {
+ FILE *p;
+ static char output[50000];
+ char line[1024];
+ int rc;
+
+ rfbLog("running pipe:\n %s\n", cmd);
+ p = popen(cmd, "r");
+
+ output[0] = '\0';
+
+ while (fgets(line, 1024, p) != NULL) {
+ if (strlen(output) + strlen(line) + 1 < 50000) {
+ strcat(output, line);
+ }
+ }
+ rc = pclose(p);
+ return(output);
+}
+
+void solid_root(char *color) {
+ Window expose;
+ static XImage *image = NULL;
+ Pixmap pixmap;
+ XGCValues gcv;
+ GC gc;
+ XSetWindowAttributes swa;
+ Visual visual;
+ unsigned long mask, pixel;
+ XColor cdef;
+ Colormap cmap;
+
+ if (subwin || window != rootwin) {
+ rfbLog("cannot set subwin to solid color, must be root\n");
+ return;
+ }
+
+ /* create the "clear" window just for generating exposures */
+ swa.override_redirect = True;
+ swa.backing_store = NotUseful;
+ swa.save_under = False;
+ swa.background_pixmap = None;
+ visual.visualid = CopyFromParent;
+ mask = (CWOverrideRedirect|CWBackingStore|CWSaveUnder|CWBackPixmap);
+ expose = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth,
+ InputOutput, &visual, mask, &swa);
+
+ if (! color) {
+ /* restore the root window from the XImage snapshot */
+ pixmap = XCreatePixmap(dpy, window, dpy_x, dpy_y, depth);
+
+ if (! image) {
+ /* whoops */
+ XDestroyWindow(dpy, expose);
+ rfbLog("no root snapshot available.\n");
+ return;
+ }
+
+
+ /* draw the image to a pixmap: */
+ gcv.function = GXcopy;
+ gcv.plane_mask = AllPlanes;
+ gc = XCreateGC(dpy, window, GCFunction|GCPlaneMask, &gcv);
+
+ XPutImage(dpy, pixmap, gc, image, 0, 0, 0, 0, dpy_x, dpy_y);
+
+ gcv.foreground = gcv.background = BlackPixel(dpy, scr);
+ gc = XCreateGC(dpy, window, GCForeground|GCBackground, &gcv);
+
+ rfbLog("restoring root snapshot...\n");
+ /* set the pixmap as the bg: */
+ XSetWindowBackgroundPixmap(dpy, window, pixmap);
+ XFreePixmap(dpy, pixmap);
+ XClearWindow(dpy, window);
+ XFlush(dpy);
+
+ /* generate exposures */
+ XMapWindow(dpy, expose);
+ XSync(dpy, False);
+ XDestroyWindow(dpy, expose);
+ return;
+ }
+
+ if (! image) {
+ /* need to retrieve a snapshot of the root background: */
+ Window iwin;
+ XSetWindowAttributes iswa;
+
+ /* create image window: */
+ iswa.override_redirect = True;
+ iswa.backing_store = NotUseful;
+ iswa.save_under = False;
+ iswa.background_pixmap = None;
+ iswa.background_pixmap = ParentRelative;
+
+ iwin = XCreateWindow(dpy, window, 0, 0, dpy_x, dpy_y, 0, depth,
+ InputOutput, &visual, mask, &iswa);
+
+ rfbLog("snapshotting background...\n");
+
+ XMapWindow(dpy, iwin);
+ XSync(dpy, False);
+ image = XGetImage(dpy, iwin, 0, 0, dpy_x, dpy_y, AllPlanes,
+ ZPixmap);
+ XSync(dpy, False);
+ XDestroyWindow(dpy, iwin);
+ }
+
+ /* use black for low colors or failure */
+ pixel = BlackPixel(dpy, scr);
+ if (depth > 8 || strcmp(color, solid_default)) {
+ cmap = DefaultColormap (dpy, scr);
+ if (XParseColor(dpy, cmap, color, &cdef) &&
+ XAllocColor(dpy, cmap, &cdef)) {
+ pixel = cdef.pixel;
+ } else {
+ rfbLog("error parsing/allocing color: %s\n", color);
+ }
+ }
+
+ rfbLog("setting solid background...\n");
+ XSetWindowBackground(dpy, window, pixel);
+ XMapWindow(dpy, expose);
+ XSync(dpy, False);
+ XDestroyWindow(dpy, expose);
+}
+
+void solid_gnome(char *color) {
+ char get_color[] = "gconftool-2 --get "
+ "/desktop/gnome/background/primary_color";
+ char set_color[] = "gconftool-2 --set "
+ "/desktop/gnome/background/primary_color --type string '%s'";
+ char get_option[] = "gconftool-2 --get "
+ "/desktop/gnome/background/picture_options";
+ char set_option[] = "gconftool-2 --set "
+ "/desktop/gnome/background/picture_options --type string '%s'";
+ static char *orig_color = NULL;
+ static char *orig_option = NULL;
+ char *cmd;
+
+ if (! color) {
+ if (! orig_color) {
+ orig_color = strdup("#FFFFFF");
+ }
+ if (! orig_option) {
+ orig_option = strdup("stretched");
+ }
+ if (strstr(orig_color, "'") != NULL) {
+ rfbLog("bad color: %s\n", orig_color);
+ return;
+ }
+ if (strstr(orig_option, "'") != NULL) {
+ rfbLog("bad option: %s\n", orig_option);
+ return;
+ }
+ cmd = (char *)malloc(strlen(set_option) - 2 +
+ strlen(orig_option) + 1);
+ sprintf(cmd, set_option, orig_option);
+ do_cmd(cmd);
+ free(cmd);
+ cmd = (char *)malloc(strlen(set_color) - 2 +
+ strlen(orig_color) + 1);
+ sprintf(cmd, set_color, orig_color);
+ do_cmd(cmd);
+ free(cmd);
+ return;
+ }
+
+ if (! orig_color) {
+ char *q;
+ orig_color = strdup(cmd_output(get_color));
+ if (*orig_color == '\0') {
+ orig_color = strdup("#FFFFFF");
+ }
+ if ((q = strchr(orig_color, '\n')) != NULL) {
+ *q = '\0';
+ }
+ }
+ if (! orig_option) {
+ char *q;
+ orig_option = strdup(cmd_output(get_option));
+ if (*orig_option == '\0') {
+ orig_option = strdup("stretched");
+ }
+ if ((q = strchr(orig_option, '\n')) != NULL) {
+ *q = '\0';
+ }
+ }
+ if (strstr(color, "'") != NULL) {
+ rfbLog("bad color: %s\n", color);
+ return;
+ }
+ cmd = (char *)malloc(strlen(set_color) - 2 + strlen(color) + 1);
+ sprintf(cmd, set_color, color);
+ do_cmd(cmd);
+ free(cmd);
+ cmd = (char *)malloc(strlen(set_option) - 2 + strlen("none") + 1);
+ sprintf(cmd, set_option, "none");
+ do_cmd(cmd);
+ free(cmd);
+}
+
+void solid_kde(char *color) {
+ char set_color[] = "dcop kdesktop KBackgroundIface setColor '%s' 1";
+ char bg_off[] = "dcop kdesktop KBackgroundIface setBackgroundEnabled 0";
+ char bg_on[] = "dcop kdesktop KBackgroundIface setBackgroundEnabled 1";
+ char *cmd;
+
+ if (! color) {
+ do_cmd(bg_on);
+ return;
+ }
+
+ if (strstr(color, "'") != NULL) {
+ rfbLog("bad color: %s\n", color);
+ return;
+ }
+
+ cmd = (char *)malloc(strlen(set_color) - 2 + strlen(color) + 1);
+ sprintf(cmd, set_color, color);
+ do_cmd(cmd);
+ do_cmd(bg_off);
+ free(cmd);
+}
+
+char *guess_desktop() {
+ Atom prop;
+ prop = XInternAtom(dpy, "_QT_DESKTOP_PROPERTIES", True);
+ if (prop != None) {
+ return "kde";
+ }
+ prop = XInternAtom(dpy, "NAUTILUS_DESKTOP_WINDOW_ID", True);
+ if (prop != None) {
+ return "gnome";
+ }
+ return "root";
+}
+
+void solid_bg(int restore) {
+ static int desktop = -1;
+ static int solid_on = 0;
+ static char *prev_str;
+ char *dtname, *color;
+
+ if (restore) {
+ if (! solid_on) {
+ return;
+ }
+ if (desktop == 0) {
+ solid_root(NULL);
+ } else if (desktop == 1) {
+ solid_gnome(NULL);
+ } else if (desktop == 2) {
+ solid_kde(NULL);
+ }
+ solid_on = 0;
+ return;
+ }
+ if (! solid_str) {
+ return;
+ }
+ if (solid_on && !strcmp(prev_str, solid_str)) {
+ return;
+ }
+ if (strstr(solid_str, "guess:") == solid_str
+ || !strchr(solid_str, ':')) {
+ dtname = guess_desktop();
+ rfbLog("guessed desktop: %s\n", dtname);
+ } else {
+ if (strstr(solid_str, "gnome:") == solid_str) {
+ dtname = "gnome";
+ } else if (strstr(solid_str, "kde:") == solid_str) {
+ dtname = "kde";
+ } else {
+ dtname = "root";
+ }
+ }
+
+ color = strchr(solid_str, ':');
+ if (! color) {
+ color = solid_str;
+ } else {
+ color++;
+ if (*color == '\0') {
+ color = solid_default;
+ }
+ }
+ if (!strcmp(dtname, "gnome")) {
+ desktop = 1;
+ solid_gnome(color);
+ } else if (!strcmp(dtname, "kde")) {
+ desktop = 2;
+ solid_kde(color);
+ } else {
+ desktop = 0;
+ solid_root(color);
+ }
+ if (prev_str) {
+ free(prev_str);
+ }
+ prev_str = strdup(solid_str);
+ solid_on = 1;
+}
+
/* -- xinerama.c -- */
/*
* routines related to xinerama and blacking out rectangles
@@ -14457,7 +14848,7 @@ static void watch_loop(void) {
/*
* text printed out under -help option
*/
-static void print_help(void) {
+static void print_help(int mode) {
char help[] =
"\n"
"x11vnc: allow VNC connections to real X11 displays. %s\n"
@@ -14706,6 +15097,19 @@ static void print_help(void) {
" just use 1 shm tile for polling. Limits shm segments\n"
" used to 3.\n"
"\n"
+"-solid [color] To improve performance, when VNC clients are connected\n"
+" try to change the desktop background to a solid color.\n"
+" The [color] is optional: the default color is \"cyan4\".\n"
+" For a different one specify the X color (rgb.txt name,\n"
+" e.g. \"darkblue\" or numerical \"#RRGGBB\"). Currently\n"
+" this option only works on GNOME, KDE, and classic X\n"
+" (i.e. with the background image on the root window).\n"
+" The \"gconftool-2\" and \"dcop\" external commands are\n"
+" run for GNOME and KDE respectively. Other desktops\n"
+" won't work, e.g. XFCE (send us the corresponding\n"
+" commands if you find them). If x11vnc guesses your\n"
+" desktop incorrectly, you can force it by prefixing\n"
+" color with \"gnome:\", \"kde:\", or \"root:\".\n"
"-blackout string Black out rectangles on the screen. \"string\" is a\n"
" comma separated list of WxH+X+Y type geometries for\n"
" each rectangle.\n"
@@ -14758,6 +15162,7 @@ static void print_help(void) {
"-rc filename Use \"filename\" instead of $HOME/.x11vncrc for rc file.\n"
"-norc Do not process any .x11vncrc file for options.\n"
"-h, -help Print this help text.\n"
+"-?, -opts Only list the x11vnc options.\n"
"-V, -version Print program version (last modification date).\n"
"\n"
"-q Be quiet by printing less informational output to\n"
@@ -15024,11 +15429,11 @@ static void print_help(void) {
" available in -threads mode which has its own pointer\n"
" event handling mechanism.\n"
"\n"
-" To try out the different pointer modes to see\n"
-" which one gives the best response for your usage,\n"
-" it is convenient to use the remote control function,\n"
-" e.g. \"x11vnc -R pointer_mode:4\" or the tcl/tk gui\n"
-" (Tuning -> pointer_mode -> n).\n"
+" To try out the different pointer modes to see which\n"
+" one gives the best response for your usage, it is\n"
+" convenient to use the remote control function, for\n"
+" example \"x11vnc -R pm:4\" or the tcl/tk gui (Tuning ->\n"
+" pointer_mode -> n).\n"
"\n"
"-input_skip n For the pointer handling when non-threaded: try to\n"
" read n user input events before scanning display. n < 0\n"
@@ -15239,6 +15644,9 @@ static void print_help(void) {
" onetile enable -onetile mode. (you may need to\n"
" set shm for this to do something)\n"
" noonetile disable -onetile mode.\n"
+" solid enable -solid mode\n"
+" nosolid disable -solid mode.\n"
+" solid_color:color set -solid color (and apply it).\n"
" blackout:str set -blackout \"str\" (empty to disable).\n"
" See -blackout for the form of \"str\"\n"
" (basically: WxH+X+Y,...)\n"
@@ -15277,7 +15685,6 @@ static void print_help(void) {
" fb disable -nofb mode.\n"
" bell enable bell (if supported).\n"
" nobell disable bell.\n"
-" bell enable bell (if supported).\n"
" nosel enable -nosel mode.\n"
" sel disable -nosel mode.\n"
" noprimary enable -noprimary mode.\n"
@@ -15385,17 +15792,18 @@ static void print_help(void) {
" nowaitmapped flashcmap noflashcmap truecolor notruecolor\n"
" overlay nooverlay overlay_cursor overlay_yescursor\n"
" nooverlay_nocursor nooverlay_cursor nooverlay_yescursor\n"
-" overlay_nocursor visual scale viewonly noviewonly shared\n"
-" noshared forever noforever once timeout deny lock nodeny\n"
-" unlock connect allowonce allow localhost nolocalhost\n"
-" accept gone shm noshm flipbyteorder noflipbyteorder\n"
-" onetile noonetile blackout xinerama noxinerama xrandr\n"
-" noxrandr xrandr_mode padgeom quiet q noquiet modtweak\n"
-" nomodtweak xkb noxkb skip_keycodes add_keysyms\n"
-" noadd_keysyms clear_mods noclear_mods clear_keys\n"
-" noclear_keys remap repeat norepeat fb nofb bell nobell\n"
-" sel nosel primary noprimary cursorshape nocursorshape\n"
-" cursorpos nocursorpos cursor show_cursor noshow_cursor\n"
+" overlay_nocursor visual scale viewonly noviewonly\n"
+" shared noshared forever noforever once timeout deny\n"
+" lock nodeny unlock connect allowonce allow localhost\n"
+" nolocalhost accept gone shm noshm flipbyteorder\n"
+" noflipbyteorder onetile noonetile solid_color solid\n"
+" nosolid blackout xinerama noxinerama xrandr noxrandr\n"
+" xrandr_mode padgeom quiet q noquiet modtweak nomodtweak\n"
+" xkb noxkb skip_keycodes add_keysyms noadd_keysyms\n"
+" clear_mods noclear_mods clear_keys noclear_keys\n"
+" remap repeat norepeat fb nofb bell nobell sel nosel\n"
+" primary noprimary cursorshape nocursorshape cursorpos\n"
+" nocursorpos cursor show_cursor noshow_cursor\n"
" nocursor xfixes noxfixes alphacut alphafrac\n"
" alpharemove noalpharemove alphablend noalphablend\n"
" xwarp xwarppointer noxwarp noxwarppointer buttonmap\n"
@@ -15473,6 +15881,31 @@ static void print_help(void) {
;
/* have both our help and rfbUsage to stdout for more(1), etc. */
dup2(1, 2);
+
+ if (mode == 1) {
+ char *p;
+ int l = 0;
+ fprintf(stderr, "x11vnc: allow VNC connections to real "
+ "X11 displays. %s\n\nx11vnc options:\n", lastmod);
+ p = strtok(help, "\n");
+ while (p) {
+ int w = 23;
+ char tmp[100];
+ if (p[0] == '-') {
+ strncpy(tmp, p, w);
+ fprintf(stderr, " %s", tmp);
+ l++;
+ if (l % 2 == 0) {
+ fprintf(stderr, "\n");
+ }
+ }
+ p = strtok(NULL, "\n");
+ }
+ fprintf(stderr, "\n\nlibvncserver options:\n");
+ rfbUsage();
+ fprintf(stderr, "\n");
+ exit(1);
+ }
fprintf(stderr, help, lastmod,
view_only ? "on":"off",
shared ? "on":"off",
@@ -15503,6 +15936,9 @@ static void print_help(void) {
void set_vnc_desktop_name(void) {
int sz = 256;
sprintf(vnc_desktop_name, "unknown");
+ if (inetd) {
+ sprintf(vnc_desktop_name, "inetd-no-further-clients");
+ }
if (screen->port) {
char *host = this_host();
int lport = screen->port;
@@ -15827,6 +16263,8 @@ int main(int argc, char* argv[]) {
argv_vnc[0] = strdup(argv[0]);
program_name = strdup(argv[0]);
+ solid_default = strdup(solid_default); /* for freeing with -R */
+
len = 0;
for (i=1; i < argc; i++) {
len += strlen(argv[i]) + 4 + 1;
@@ -15970,6 +16408,18 @@ int main(int argc, char* argv[]) {
flip_byte_order = 1;
} else if (!strcmp(arg, "-onetile")) {
single_copytile = 1;
+ } else if (!strcmp(arg, "-solid")) {
+ use_solid_bg = 1;
+ if (i < argc-1) {
+ char *s = argv[i+1];
+ if (s[0] != '-') {
+ solid_str = strdup(s);
+ i++;
+ }
+ }
+ if (! solid_str) {
+ solid_str = strdup(solid_default);
+ }
} else if (!strcmp(arg, "-blackout")) {
CHECK_ARGC
blackout_str = strdup(argv[++i]);
@@ -16000,9 +16450,10 @@ int main(int argc, char* argv[]) {
i++; /* done above */
} else if (!strcmp(arg, "-norc")) {
; /* done above */
- } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")
- || !strcmp(arg, "-?")) {
- print_help();
+ } else if (!strcmp(arg, "-h") || !strcmp(arg, "-help")) {
+ print_help(0);
+ } else if (!strcmp(arg, "-?") || !strcmp(arg, "-opts")) {
+ print_help(1);
} else if (!strcmp(arg, "-V") || !strcmp(arg, "-version")) {
fprintf(stderr, "x11vnc: %s\n", lastmod);
exit(0);
@@ -16270,7 +16721,6 @@ int main(int argc, char* argv[]) {
}
-
/*
* If -passwd was used, clear it out of argv. This does not
* work on all UNIX, have to use execvp() in general...
@@ -16480,6 +16930,8 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " using_shm: %d\n", using_shm);
fprintf(stderr, " flipbytes: %d\n", flip_byte_order);
fprintf(stderr, " onetile: %d\n", single_copytile);
+ fprintf(stderr, " solid: %s\n", solid_str
+ ? solid_str : "null");
fprintf(stderr, " blackout: %s\n", blackout_str
? blackout_str : "null");
fprintf(stderr, " xinerama: %d\n", xinerama);
@@ -16491,7 +16943,7 @@ int main(int argc, char* argv[]) {
fprintf(stderr, " logfile: %s\n", logfile ? logfile
: "null");
fprintf(stderr, " logappend: %d\n", logfile_append);
- fprintf(stderr, " rc_file: \%s\n", rc_rcfile ? rc_rcfile
+ fprintf(stderr, " rc_file: %s\n", rc_rcfile ? rc_rcfile
: "null");
fprintf(stderr, " norc: %d\n", rc_norc);
fprintf(stderr, " bg: %d\n", bg);