/* -- gui.c -- */ #include "x11vnc.h" #include "xevents.h" #include "win_utils.h" #include "remote.h" #include "cleanup.h" #include "xwrappers.h" #include "connections.h" #include "tkx11vnc.h" #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 #define XEMBED_VERSION 0 #define XEMBED_MAPPED (1 << 0) int icon_mode = 0; /* hack for -gui tray/icon */ char *icon_mode_file = NULL; FILE *icon_mode_fh = NULL; int icon_mode_socks[ICON_MODE_SOCKS]; int tray_manager_ok = 0; Window tray_request = None; Window tray_window = None; int tray_unembed = 0; pid_t run_gui_pid = 0; pid_t gui_pid = 0; char *get_gui_code(void); int tray_embed(Window iconwin, int remove); void do_gui(char *opts, int sleep); static Window tweak_tk_window_id(Window win); static int tray_manager_running(Display *d, Window *manager); static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc, int simple_gui, pid_t parent, char *gui_opts); char *get_gui_code(void) { return gui_code; } static Window tweak_tk_window_id(Window win) { #if NO_X11 if (!win) {} return None; #else char *name = NULL; Window parent, new; if (getenv("NO_TWEAK_TK_WINDOW_ID")) { return win; } /* hack for tk, does not report outermost window */ new = win; parent = parent_window(win, &name); if (parent && name != NULL) { lowercase(name); if (strstr(name, "wish") || strstr(name, "x11vnc")) { new = parent; rfbLog("tray_embed: using parent: %s\n", name); } } if (name != NULL) { XFree_wr(name); } return new; #endif /* NO_X11 */ } int tray_embed(Window iconwin, int remove) { #if NO_X11 RAWFB_RET(0) if (!iconwin || !remove) {} return 0; #else XEvent ev; XErrorHandler old_handler; Window manager; Atom xembed_info; Atom tatom; XWindowAttributes attr; long info[2] = {XEMBED_VERSION, XEMBED_MAPPED}; long data = 0; RAWFB_RET(0) if (remove) { if (!valid_window(iconwin, &attr, 1)) { return 0; } iconwin = tweak_tk_window_id(iconwin); trapped_xerror = 0; old_handler = XSetErrorHandler(trap_xerror); /* * unfortunately no desktops seem to obey this * part of the XEMBED spec yet... */ XReparentWindow(dpy, iconwin, rootwin, 0, 0); XSetErrorHandler(old_handler); if (trapped_xerror) { trapped_xerror = 0; return 0; } trapped_xerror = 0; return 1; } xembed_info = XInternAtom(dpy, "_XEMBED_INFO", False); if (xembed_info == None) { return 0; } if (!tray_manager_running(dpy, &manager)) { return 0; } memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.window = manager; ev.xclient.message_type = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False); ev.xclient.format = 32; ev.xclient.data.l[0] = CurrentTime; ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK; ev.xclient.data.l[2] = iconwin; ev.xclient.data.l[3] = 0; ev.xclient.data.l[4] = 0; if (!valid_window(iconwin, &attr, 1)) { return 0; } iconwin = tweak_tk_window_id(iconwin); ev.xclient.data.l[2] = iconwin; XUnmapWindow(dpy, iconwin); trapped_xerror = 0; old_handler = XSetErrorHandler(trap_xerror); XSendEvent(dpy, manager, False, NoEventMask, &ev); XSync(dpy, False); if (trapped_xerror) { XSetErrorHandler(old_handler); trapped_xerror = 0; return 0; } XChangeProperty(dpy, iconwin, xembed_info, xembed_info, 32, PropModeReplace, (unsigned char *)&info, 2); #if 0 { XSizeHints *xszh = XAllocSizeHints(); xszh->flags = PMinSize; xszh->min_width = 24; xszh->min_height = 24; XSetWMNormalHints(dpy, iconwin, xszh); } #endif /* kludge for KDE evidently needed... */ tatom = XInternAtom(dpy, "KWM_DOCKWINDOW", False); XChangeProperty(dpy, iconwin, tatom, tatom, 32, PropModeReplace, (unsigned char *)&data, 1); tatom = XInternAtom(dpy, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False); XChangeProperty(dpy, iconwin, tatom, XA_WINDOW, 32, PropModeReplace, (unsigned char *)&data, 1); XSetErrorHandler(old_handler); trapped_xerror = 0; return 1; #endif /* NO_X11 */ } static int tray_manager_running(Display *d, Window *manager) { #if NO_X11 RAWFB_RET(0) if (!d || !manager) {} return 0; #else char tray_string[100]; Atom tray_manager; Window tray_win; RAWFB_RET(0) if (manager) { *manager = None; } sprintf(tray_string, "_NET_SYSTEM_TRAY_S%d", scr); tray_manager = XInternAtom(d, tray_string, True); if (tray_manager == None) { return 0; } tray_win = XGetSelectionOwner(d, tray_manager); if (manager) { *manager = tray_win; } if (tray_win == None) { return 0; } else { return 1; } #endif /* NO_X11 */ } static char *gui_geometry = NULL; static int icon_in_tray = 0; static char *icon_mode_embed_id = NULL; static char *icon_mode_font = NULL; static char *icon_mode_params = NULL; static int got_sigusr1 = 0; static void sigusr1 (int sig) { got_sigusr1 = 1; if (0) sig = 0; } static char *extra_path = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin" ":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin"; static char *wishes[] = {"wish8.4", "wish", "wish8.3", "wish8.5", "wish8.0", NULL}; static void run_gui(char *gui_xdisplay, int connect_to_x11vnc, int start_x11vnc, int simple_gui, pid_t parent, char *gui_opts) { char *x11vnc_xdisplay = NULL; char cmd[100]; char *wish = NULL, *orig_path, *full_path, *tpath, *p; char *old_xauth = NULL; int try_max = 4, sleep = 300, totms, rc = 0; pid_t mypid = getpid(); FILE *pipe, *tmpf; if (0) fprintf(stderr, "run_gui: %s -- %d %d\n", gui_xdisplay, connect_to_x11vnc, (int) parent); if (*gui_code == '\0') { rfbLog("gui: gui not compiled into this program.\n"); exit(0); } if (getenv("DISPLAY") != NULL) { /* worst case */ x11vnc_xdisplay = strdup(getenv("DISPLAY")); } if (use_dpy) { /* better */ x11vnc_xdisplay = strdup(use_dpy); } if (connect_to_x11vnc) { int i; rfbLogEnable(1); if (! client_connect_file) { if (getenv("XAUTHORITY") != NULL) { old_xauth = strdup(getenv("XAUTHORITY")); } else { old_xauth = strdup(""); } dpy = XOpenDisplay_wr(x11vnc_xdisplay); if (! dpy && auth_file) { set_env("XAUTHORITY", auth_file); dpy = XOpenDisplay_wr(x11vnc_xdisplay); } if (! dpy && ! x11vnc_xdisplay) { /* worstest case */ x11vnc_xdisplay = strdup(":0"); dpy = XOpenDisplay_wr(x11vnc_xdisplay); } if (! dpy) { rfbLog("gui: could not open x11vnc " "display: %s\n", NONUL(x11vnc_xdisplay)); #ifdef MACOSX goto macjump; #endif exit(1); } scr = DefaultScreen(dpy); rootwin = RootWindow(dpy, scr); initialize_vnc_connect_prop(); initialize_x11vnc_remote_prop(); } #ifdef MACOSX macjump: #endif signal(SIGUSR1, sigusr1); got_sigusr1 = 0; totms = 0; while (totms < 3500) { usleep(50*1000); totms += 50; if (got_sigusr1) { fprintf(stderr, "\n"); if (! quiet) rfbLog("gui: got SIGUSR1\n"); break; } if (! start_x11vnc && totms >= 150) { break; } } signal(SIGUSR1, SIG_DFL); if (! got_sigusr1) fprintf(stderr, "\n"); if (!quiet && ! got_sigusr1) { rfbLog("gui: trying to contact a x11vnc server at X" " display %s ...\n", NONUL(x11vnc_xdisplay)); } for (i=0; i %s", p1, wish, tf1, tf2); } else { sprintf(cmd, "env PATH='%s' DISPLAY='%s' %s %s -name x11vnc_port_prompt -portprompt > %s", p1, dstr, wish, tf1, tf2); } if (getenv("X11VNC_DEBUG_PORTPROMPT")) { fprintf(stderr, "cmd=%s\n", cmd); } if (use_openssl) { set_env("X11VNC_SSL_ENABLED", "1"); } if (allow_list && !strcmp(allow_list, "127.0.0.1")) { set_env("X11VNC_LOCALHOST_ENABLED", "1"); } if (got_ultrafilexfer) { set_env("X11VNC_FILETRANSFER_ENABLED", "ultra"); } else if (tightfilexfer) { set_env("X11VNC_FILETRANSFER_ENABLED", "tight"); } system(cmd); free(cmd); free(p1); fp = fopen(tf2, "r"); memset(line, 0, sizeof(line)); if (fp) { fgets(line, 128, fp); fclose(fp); if (line[0] != '\0') { int readport = atoi(line); if (readport > 0) { got_rfbport_val = readport; } } } if (strstr(line, "ssl0")) { if (use_openssl) use_openssl = 0; } else if (strstr(line, "ssl1")) { if (!use_openssl) { use_openssl = 1; openssl_pem = strdup("SAVE_NOPROMPT"); set_env("X11VNC_GOT_SSL", "1"); } } if (strstr(line, "localhost0")) { if (allow_list && !strcmp(allow_list, "127.0.0.1")) { allow_list = NULL; } } else if (strstr(line, "localhost1")) { allow_list = strdup("127.0.0.1"); } if (strstr(line, "ft_ultra")) { got_ultrafilexfer = 1; tightfilexfer = 0; } else if (strstr(line, "ft_tight")) { got_ultrafilexfer = 0; tightfilexfer = 1; } else if (strstr(line, "ft_none")) { got_ultrafilexfer = 0; tightfilexfer = 0; } unlink(tf1); unlink(tf2); if (old_xauth) { set_env("XAUTHORITY", old_xauth); } return; } if (start_x11vnc) { #if LIBVNCSERVER_HAVE_FORK /* fork into the background now */ int p; pid_t parent = getpid(); if (icon_mode) { char tf[] = "/tmp/x11vnc.tray.XXXXXX"; int fd; struct stat sbuf; fd = mkstemp(tf); if (fd < 0) { icon_mode = 0; } else { close(fd); icon_mode_fh = fopen(tf, "w"); if (! icon_mode_fh) { icon_mode = 0; } else { chmod(tf, 0400); icon_mode_file = strdup(tf); rfbLog("icon_mode_file=%s\n", icon_mode_file); fprintf(icon_mode_fh, "none\n"); fprintf(icon_mode_fh, "none\n"); fflush(icon_mode_fh); if (! got_connect_once) { if (!client_connect && !connect_or_exit) { /* want -forever for tray? */ connect_once = 0; } } } } } if ((p = fork()) > 0) { ; /* parent */ } else if (p == -1) { fprintf(stderr, "could not fork\n"); perror("fork"); clean_up_exit(1); } else { if (sleep > 0) { usleep(sleep * 1000 * 1000); } run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc, simple_gui, parent, opts); exit(1); } if (connect_to_x11vnc) { run_gui_pid = p; gui_pid = p; } #else fprintf(stderr, "system does not support fork: start " "x11vnc in the gui.\n"); start_x11vnc = 0; #endif } if (!start_x11vnc) { run_gui(gui_xdisplay, connect_to_x11vnc, start_x11vnc, simple_gui, 0, opts); exit(1); } if (old_xauth) { set_env("XAUTHORITY", old_xauth); } }