Commit 98f8a224 authored by Chris Coulson's avatar Chris Coulson Committed by William Jon McCann

Work around x errors by asking dialog to die on cancel

Basically, what is happening is that gnome-screensaver-dialog exits after the
5th failed attempt at unlocking the screen, but before the shake animation
finishes. If the timing is slightly unlucky, this results in gnome-screensaver
accessing X resources that have already been destroyed (I ran it through
xtrace, and that showed this happening)

My patch fixes this by making gnome-screensaver-dialog request to
gnome-screensaver that it be terminated after the 5th failed attempt (rather
than exitting straight away, although there is a fallback timeout too).
gnome-screensaver then terminates the dialog after it is finished with the
shake animation, to avoid the race condition that is currently making it crash.
parent 0f4f0934
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
#include <glib/gi18n.h> #include <glib/gi18n.h>
#include <gdk/gdkx.h> #include <gdk/gdkx.h>
...@@ -325,6 +326,21 @@ response_cb (GSLockPlug *plug, ...@@ -325,6 +326,21 @@ response_cb (GSLockPlug *plug,
} }
} }
static gboolean
response_request_quit (void)
{
printf ("REQUEST QUIT\n");
fflush (stdout);
return FALSE;
}
static gboolean
quit_timeout_cb (gpointer data)
{
gtk_main_quit ();
return FALSE;
}
static gboolean static gboolean
auth_check_idle (GSLockPlug *plug) auth_check_idle (GSLockPlug *plug)
{ {
...@@ -347,7 +363,11 @@ auth_check_idle (GSLockPlug *plug) ...@@ -347,7 +363,11 @@ auth_check_idle (GSLockPlug *plug)
} else { } else {
gs_debug ("Authentication failed, quitting (max failures)"); gs_debug ("Authentication failed, quitting (max failures)");
again = FALSE; again = FALSE;
gtk_main_quit (); /* Don't quit immediately, but rather request that gnome-screensaver
* terminates us after it has finished the dialog shake. Time out
* after 5 seconds and quit anyway if this doesn't happen though */
g_idle_add ((GSourceFunc)response_request_quit, NULL);
g_timeout_add (5000, (GSourceFunc)quit_timeout_cb, NULL);
} }
} }
......
...@@ -91,6 +91,8 @@ struct GSWindowPrivate ...@@ -91,6 +91,8 @@ struct GSWindowPrivate
gint lock_pid; gint lock_pid;
gint lock_watch_id; gint lock_watch_id;
gint dialog_response; gint dialog_response;
gboolean dialog_quit_requested;
gboolean dialog_shake_in_progress;
gint keyboard_pid; gint keyboard_pid;
gint keyboard_watch_id; gint keyboard_watch_id;
...@@ -1383,6 +1385,16 @@ gs_window_dialog_finish (GSWindow *window) ...@@ -1383,6 +1385,16 @@ gs_window_dialog_finish (GSWindow *window)
remove_key_events (window); remove_key_events (window);
} }
static void
maybe_kill_dialog (GSWindow *window)
{
if (!window->priv->dialog_shake_in_progress
&& window->priv->dialog_quit_requested
&& window->priv->lock_pid > 0) {
kill (window->priv->lock_pid, SIGTERM);
}
}
/* very rudimentary animation for indicating an auth failure */ /* very rudimentary animation for indicating an auth failure */
static void static void
shake_dialog (GSWindow *window) shake_dialog (GSWindow *window)
...@@ -1391,6 +1403,8 @@ shake_dialog (GSWindow *window) ...@@ -1391,6 +1403,8 @@ shake_dialog (GSWindow *window)
guint left; guint left;
guint right; guint right;
window->priv->dialog_shake_in_progress = TRUE;
for (i = 0; i < 9; i++) { for (i = 0; i < 9; i++) {
if (i % 2 == 0) { if (i % 2 == 0) {
left = 30; left = 30;
...@@ -1415,6 +1429,9 @@ shake_dialog (GSWindow *window) ...@@ -1415,6 +1429,9 @@ shake_dialog (GSWindow *window)
g_usleep (10000); g_usleep (10000);
} }
window->priv->dialog_shake_in_progress = FALSE;
maybe_kill_dialog (window);
} }
static gboolean static gboolean
...@@ -1457,6 +1474,10 @@ lock_command_watch (GIOChannel *source, ...@@ -1457,6 +1474,10 @@ lock_command_watch (GIOChannel *source,
window->priv->dialog_response = DIALOG_RESPONSE_CANCEL; window->priv->dialog_response = DIALOG_RESPONSE_CANCEL;
} }
finished = TRUE; finished = TRUE;
} else if (strstr (line, "REQUEST QUIT") != NULL) {
gs_debug ("Got request for quit");
window->priv->dialog_quit_requested = TRUE;
maybe_kill_dialog (window);
} }
break; break;
case G_IO_STATUS_EOF: case G_IO_STATUS_EOF:
...@@ -1570,6 +1591,9 @@ popup_dialog_idle (GSWindow *window) ...@@ -1570,6 +1591,9 @@ popup_dialog_idle (GSWindow *window)
set_invisible_cursor (GTK_WIDGET (window)->window, FALSE); set_invisible_cursor (GTK_WIDGET (window)->window, FALSE);
window->priv->dialog_quit_requested = FALSE;
window->priv->dialog_shake_in_progress = FALSE;
result = spawn_on_window (window, result = spawn_on_window (window,
command->str, command->str,
&window->priv->lock_pid, &window->priv->lock_pid,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment