/* -- gui.c -- */ #include "x11vnc.h" #include "xevents.h" #include "win_utils.h" #include "remote.h" #include "cleanup.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; 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) { char *name = NULL; Window parent, new; /* 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(name); } return new; } int tray_embed(Window iconwin, int remove) { XEvent ev; XErrorHandler old_handler; Window manager; Atom xembed_info; Atom tatom; XWindowAttributes attr; long info[2] = {XEMBED_VERSION, XEMBED_MAPPED}; long data = 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); /* 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; } static int tray_manager_running(Display *d, Window *manager) { char tray_string[100]; Atom tray_manager; Window tray_win; 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; } } 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 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 extra_path[] = ":/usr/local/bin:/usr/bin/X11:/usr/sfw/bin" ":/usr/X11R6/bin:/usr/openwin/bin:/usr/dt/bin"; char cmd[100]; char *wish = NULL, *orig_path, *full_path, *tpath, *p; char *old_xauth = NULL; int try_max = 4, sleep = 300; pid_t mypid = getpid(); FILE *pipe, *tmpf; 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 rc, i; rfbLogEnable(1); if (! client_connect_file) { if (getenv("XAUTHORITY") != NULL) { old_xauth = strdup(getenv("XAUTHORITY")); } else { old_xauth = strdup(""); } dpy = XOpenDisplay(x11vnc_xdisplay); if (! dpy && auth_file) { set_env("XAUTHORITY", auth_file); dpy = XOpenDisplay(x11vnc_xdisplay); } if (! dpy && ! x11vnc_xdisplay) { /* worstest case */ x11vnc_xdisplay = strdup(":0"); dpy = XOpenDisplay(x11vnc_xdisplay); } if (! dpy) { rfbLog("gui: could not open x11vnc " "display: %s\n", NONUL(x11vnc_xdisplay)); exit(1); } scr = DefaultScreen(dpy); rootwin = RootWindow(dpy, scr); initialize_vnc_connect_prop(); } usleep(2200*1000); fprintf(stderr, "\n"); if (!quiet) { rfbLog("gui: trying to contact a x11vnc server at X" " display %s ...\n", NONUL(x11vnc_xdisplay)); } for (i=0; i