summaryrefslogtreecommitdiffstats
path: root/x11vnc/xevents.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/xevents.c')
-rw-r--r--x11vnc/xevents.c220
1 files changed, 209 insertions, 11 deletions
diff --git a/x11vnc/xevents.c b/x11vnc/xevents.c
index c1389ad..d7ce8fe 100644
--- a/x11vnc/xevents.c
+++ b/x11vnc/xevents.c
@@ -77,6 +77,7 @@ void set_text_chat(rfbClientPtr cl, int l, char *t);
int get_keyboard_led_state_hook(rfbScreenInfoPtr s);
int get_file_transfer_permitted(rfbClientPtr cl);
void get_prop(char *str, int len, Atom prop, Window w);
+int guess_dm_gone(int t1, int t2);
static void initialize_xevents(int reset);
static void print_xevent_bases(void);
@@ -119,6 +120,189 @@ void initialize_clipboard_atom(void) {
#endif /* NO_X11 */
}
+/*
+ we observed these strings:
+
+ 6 gdm_string: Gnome-power-manager
+ 6 gdm_string: Gnome-session
+ 6 gdm_string: Gnome-settings-daemon
+ 6 gdm_string: Login Window
+ 6 gdm_string: Notify-osd
+ 6 gdm_string: Panel
+ 12 gdm_string: Metacity
+ 12 gdm_string: gnome-power-manager
+ 12 gdm_string: gnome-session
+ 12 gdm_string: gnome-settings-daemon
+ 12 gdm_string: notify-osd
+ 18 gdm_string: Gdm-simple-greeter
+ 24 gdm_string: metacity
+ 36 gdm_string: gdm-simple-greeter
+ */
+
+static int gdm_string(char *str) {
+ if (str == NULL) {
+ return 0;
+ }
+ if (str[0] == '\0') {
+ return 0;
+ }
+ if (0) fprintf(stderr, "gdm_string: %s\n", str);
+ if (strstr(str, "gdm-") == str || strstr(str, "Gdm-") == str) {
+ if (strstr(str, "-greeter") != NULL) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int gdm_still_running(void) {
+#if NO_X11
+ return 0;
+#else
+ Window r, parent;
+ Window *winlist;
+ unsigned int nc;
+ int rc, i;
+ static XClassHint *classhint = NULL;
+ XErrorHandler old_handler;
+ int saw_gdm_name = 0;
+
+ /* some times a window can go away before we get to it */
+ trapped_xerror = 0;
+ old_handler = XSetErrorHandler(trap_xerror);
+
+ if (! classhint) {
+ classhint = XAllocClassHint();
+ }
+
+ /* we are xlocked. */
+ rc = XQueryTree_wr(dpy, DefaultRootWindow(dpy), &r, &parent, &winlist, &nc);
+ if (!rc || winlist == NULL || nc == 0) {
+ nc = 0;
+ }
+ for (i=0; i < (int) nc; i++) {
+ char *name = NULL;
+ Window w = winlist[i];
+ if (XFetchName(dpy, w, &name) && name != NULL) {
+ saw_gdm_name += gdm_string(name);
+ XFree_wr(name);
+ }
+ classhint->res_name = NULL;
+ classhint->res_class = NULL;
+ if (XGetClassHint(dpy, w, classhint)) {
+ name = classhint->res_name;
+ if (name != NULL) {
+ saw_gdm_name += gdm_string(name);
+ XFree_wr(name);
+ }
+ name = classhint->res_class;
+ if (name != NULL) {
+ saw_gdm_name += gdm_string(name);
+ XFree_wr(name);
+ }
+ }
+ if (saw_gdm_name > 0) {
+ break;
+ }
+ }
+ if (winlist != NULL) {
+ XFree_wr(winlist);
+ }
+
+ XSync(dpy, False);
+ XSetErrorHandler(old_handler);
+ trapped_xerror = 0;
+
+ return saw_gdm_name;
+#endif
+}
+
+static int wm_running(void) {
+ char *s = getenv("DEBUG_WM_RUNNING");
+ RAWFB_RET(0)
+#if NO_X11
+ return 0;
+#else
+ /*
+ * Unfortunately with recent GDM (v2.28), they run gnome-session,
+ * dbus-launch, and metacity for the Login greeter! So the simple
+ * XInternAtom checks below no longer work.
+ */
+ if (gdm_still_running()) {
+ return 0;
+ }
+
+ /* we are xlocked. */
+ if (XInternAtom(dpy, "_NET_SUPPORTED", True) != None) {
+ if (s) rfbLog("wm is running (_NET_SUPPORTED).\n");
+ return 1;
+ }
+ if (XInternAtom(dpy, "_WIN_PROTOCOLS", True) != None) {
+ if (s) rfbLog("wm is running (_WIN_PROTOCOLS).\n");
+ return 1;
+ }
+ if (XInternAtom(dpy, "_XROOTPMAP_ID", True) != None) {
+ if (s) rfbLog("wm is running (_XROOTPMAP_ID).\n");
+ return 1;
+ }
+ if (XInternAtom(dpy, "_MIT_PRIORITY_COLORS", True) != None) {
+ if (s) rfbLog("wm is running (_MIT_PRIORITY_COLORS).\n");
+ return 1;
+ }
+ if (s) rfbLog("wm is not running.\n");
+ return 0;
+#endif /* NO_X11 */
+
+}
+
+int guess_dm_gone(int t1, int t2) {
+ int wait = t2;
+ char *avoid = getenv("X11VNC_AVOID_WINDOWS");
+ time_t tcheck = last_client;
+
+ if (last_open_xdisplay > last_client) {
+ /* better time for -display WAIT:... */
+ tcheck = last_open_xdisplay;
+ }
+
+ if (avoid && !strcmp(avoid, "never")) {
+ return 1;
+ }
+ if (!screen || !screen->clientHead) {
+ return 0;
+ }
+ if (avoid) {
+ int n = atoi(avoid);
+ if (n > 1) {
+ wait = n;
+ } else {
+ wait = 90;
+ }
+ } else {
+ static time_t saw_wm = 0;
+
+ wait = t2;
+
+ X_LOCK;
+ if (wm_running()) {
+ if (saw_wm == 0) {
+ saw_wm = time(NULL);
+ } else if (time(NULL) <= saw_wm + 2) {
+ /* try to wait a few seconds after transition */
+ ;
+ } else {
+ wait = t1;
+ }
+ }
+ X_UNLOCK;
+ }
+ /* we assume they've logged in OK after wait seconds... */
+ if (time(NULL) <= tcheck + wait) {
+ return 0;
+ }
+ return 1;
+}
+
static void initialize_xevents(int reset) {
#if NO_X11
RAWFB_RET_VOID
@@ -162,11 +346,17 @@ static void initialize_xevents(int reset) {
if (watch_selection && !did_xcreate_simple_window) {
/* create fake window for our selection ownership, etc */
- X_LOCK;
- selwin = XCreateSimpleWindow(dpy, rootwin, 0, 0, 1, 1, 0, 0, 0);
- X_UNLOCK;
- did_xcreate_simple_window = 1;
- if (0) rfbLog("selwin: 0x%lx\n", selwin);
+ /*
+ * We try to delay creating selwin until we are past
+ * any GDM, (or other KillInitClients=true) manager.
+ */
+ if (guess_dm_gone(5, 45)) {
+ X_LOCK;
+ selwin = XCreateSimpleWindow(dpy, rootwin, 3, 2, 1, 1, 0, 0, 0);
+ X_UNLOCK;
+ did_xcreate_simple_window = 1;
+ if (! quiet) rfbLog("created selwin: 0x%lx\n", selwin);
+ }
}
if ((xrandr || xrandr_maybe) && !did_xrandr) {
@@ -190,8 +380,16 @@ static void initialize_xevents(int reset) {
did_clipboard_atom = 1;
}
if (xfixes_present && use_xfixes && !did_xfixes) {
- initialize_xfixes();
- did_xfixes = 1;
+ /*
+ * We try to delay creating initializing xfixes until
+ * we are past the display manager, due to Xorg bug:
+ * http://bugs.freedesktop.org/show_bug.cgi?id=18451
+ */
+ if (guess_dm_gone(5, 45)) {
+ initialize_xfixes();
+ did_xfixes = 1;
+ if (! quiet) rfbLog("called initialize_xfixes()\n");
+ }
}
if (xdamage_present && !did_xdamage) {
initialize_xdamage();
@@ -1182,7 +1380,7 @@ void check_xevents(int reset) {
}
#endif
#if LIBVNCSERVER_HAVE_LIBXFIXES
- if (xfixes_present && use_xfixes && xfixes_base_event_type) {
+ if (xfixes_present && use_xfixes && xfixes_first_initialized && xfixes_base_event_type) {
if (XCheckTypedEvent(dpy, xfixes_base_event_type +
XFixesCursorNotify, &xev)) {
got_xfixes_cursor_notify++;
@@ -1260,7 +1458,7 @@ void check_xevents(int reset) {
req = "CLIPBOARD";
}
if (which != 0 && ! own && have_clients &&
- XGetSelectionOwner(dpy, atom) != None) {
+ XGetSelectionOwner(dpy, atom) != None && selwin != None) {
XConvertSelection(dpy, atom, XA_STRING, XA_STRING,
selwin, CurrentTime);
if (debug_sel) {
@@ -1501,7 +1699,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
X_LOCK;
/* associate this text with PRIMARY (and SECONDARY...) */
- if (set_primary && ! own_primary) {
+ if (set_primary && ! own_primary && selwin != None) {
own_primary = 1;
/* we need to grab the PRIMARY selection */
XSetSelectionOwner(dpy, XA_PRIMARY, selwin, CurrentTime);
@@ -1511,7 +1709,7 @@ void xcut_receive(char *text, int len, rfbClientPtr cl) {
}
}
- if (set_clipboard && ! own_clipboard && clipboard_atom != None) {
+ if (set_clipboard && ! own_clipboard && clipboard_atom != None && selwin != None) {
own_clipboard = 1;
/* we need to grab the CLIPBOARD selection */
XSetSelectionOwner(dpy, clipboard_atom, selwin, CurrentTime);