Screen saver support patches



Hi,

I'd like to use GDM to start a screen saver-like program.
This would allow the machine to join a distributed computing
system when the machine is idle.

Currently in GDM one can specify a program using
greeter/BackgroundProgram. There are two shortcomings, however:

- The program is run immediately after GDM is started.

- The program is not restarted after a while when it has exited.

I patched gdmlogin to implement the following features:

- You can specify greeter/BackgroundProgramInitialDelay
 which controls when the program is run after GDM is started.

- You can specify greeter/BackgroundProgramNextDelay
 which controls when the program is restarted after it has
 exited.

Essentially, I use a timeout to start the program when it is
time, and a watcher to detect when the program has exited.
I replaced calls to gdm_run_command(), run_backgrounds(), and
gdm_kill_thingies() with their equivalents in the new API.
The logic of the program did not change much.

I'm sending diffs against version 2.6.0.8 of gdm. The
integration is not complete. In particular,

- Need to remove backgroundpid, gdm_run_command(),
 run_backgrounds() and gdm_kill_thingies() (commented out).

- Must no longer ignore SIGCHLD (commented out).

- Maybe let user specify -1 to disallow restarting?

- Documentation for the user.

The patched version works almost correctly on my system, but
there is still one problem. While the program always get
mouse focus, it does not always receive keyboard focus.
Sometimes you can login while the screen saver is running
(the screen saver gets killed, but it should go when the
user is typing).

Thanks for GDM!

Laurent Birtz

--- old/gdmlogin.c	2005-03-23 00:16:16.000000000 -0500
+++ new/gdmlogin.c	2005-03-23 00:16:26.000000000 -0500
@@ -15,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
 #include <config.h>
 
 #include <libgnome/libgnome.h>
@@ -97,6 +96,8 @@
 static gchar *GdmWelcome;
 static gchar *GdmBackgroundProg;
 static gboolean GdmRunBackgroundProgAlways;
+static gint GdmBackgroundProgInitDelay;
+static gint GdmBackgroundProgNextDelay;
 static gchar *GdmBackgroundImage;
 static gchar *GdmBackgroundColor;
 static gboolean GdmBackgroundScaleToFit;
@@ -194,6 +195,9 @@
 static gint maxheight = 0;
 
 static pid_t backgroundpid = 0;
+static gint back_prog_timeout_event_id = -1;
+static gint back_prog_watcher_event_id = -1;
+static gint back_prog_pid = -1;
 
 static guint timed_handler_id = 0;
 
@@ -206,6 +210,175 @@
 
 static void login_window_resize (gboolean force);
 
+
+/* Background program logic */
+
+static void back_prog_on_exit (GPid pid, gint status, gpointer data);
+static gboolean back_prog_on_timeout (gpointer data);
+static gchar *back_prog_get_path (void);
+static void back_prog_launch_after_timeout (int timeout);
+static void back_prog_run (void);
+static void back_prog_stop (void);
+
+/* 
+ * This function is called when the background program exits.
+ * It will add a timer to restart the program after the
+ * restart delay has elapsed.
+ */
+static void 
+back_prog_on_exit (GPid pid, gint status, gpointer data)
+{
+	g_assert (back_prog_timeout_event_id == -1);
+	
+	back_prog_watcher_event_id = -1;
+	back_prog_pid = -1;
+	back_prog_launch_after_timeout (GdmBackgroundProgNextDelay);
+}
+
+/* 
+ * This function starts the background program (if any) when
+ * the timer triggers.
+ */
+static gboolean 
+back_prog_on_timeout (gpointer data)
+{
+	g_assert (back_prog_watcher_event_id == -1);
+	g_assert (back_prog_pid == -1);
+	
+	back_prog_timeout_event_id = -1;
+	back_prog_run ();
+	
+	return FALSE;
+}
+
+/*
+ * This function returns the path of the background program 
+ * to start, if there is one. Otherwise, NULL is returned.
+ */
+static gchar *
+back_prog_get_path (void)
+{
+	if ((GdmBackgroundType == GDM_BACKGROUND_NONE ||
+	     GdmRunBackgroundProgAlways) &&
+	    ! ve_string_empty (GdmBackgroundProg)) {
+		return GdmBackgroundProg;
+	} else 
+		return NULL;
+}
+
+/* 
+ * This function creates a timer to start the background 
+ * program after the requested delay (in seconds) has elapsed.
+ */ 
+static void 
+back_prog_launch_after_timeout (int timeout)
+{
+	g_assert (back_prog_timeout_event_id == -1);
+	g_assert (back_prog_watcher_event_id == -1);
+	g_assert (back_prog_pid == -1);
+	
+	if (! back_prog_get_path ())
+		return;
+	
+	back_prog_timeout_event_id = g_timeout_add (timeout * 1000,
+						    back_prog_on_timeout,
+						    NULL);
+}
+
+/* 
+ * This function starts the background program (if any).
+ */
+static void
+back_prog_run (void)
+{
+	GPid pid = -1;
+	GError *error = NULL;
+	gchar *command = NULL;
+	gchar **back_prog_argv = NULL;
+	
+	g_assert (back_prog_timeout_event_id == -1);
+	g_assert (back_prog_watcher_event_id == -1);
+	g_assert (back_prog_pid == -1);
+	
+	command = back_prog_get_path ();
+	if (! command)
+		return;
+		
+	back_prog_argv = ve_split (command);	
+	
+	/* Don't reap child automatically: we want to catch the event. */
+	if (! g_spawn_async (".", 
+			     back_prog_argv, 
+			     NULL, 
+			     (GSpawnFlags) (G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD), 
+			     NULL, 
+			     NULL, 
+			     &pid, 
+			     &error)) {
+			    
+		GtkWidget *dialog;
+		dialog = ve_hig_dialog_new (NULL,
+					    GTK_DIALOG_MODAL,
+					    GTK_MESSAGE_ERROR,
+					    GTK_BUTTONS_OK,
+					    FALSE,
+					    _("Cannot start background program"),
+					    _("Cannot start program '%s': %s."),
+					    command,
+					    error->message);
+		gtk_widget_show_all (dialog);
+		gdm_wm_center_window (GTK_WINDOW (dialog));
+
+		gtk_dialog_run (GTK_DIALOG (dialog));
+		gtk_widget_destroy (dialog);
+		g_error_free (error);
+		g_strfreev (back_prog_argv);
+		
+		return;
+	}
+	
+	g_strfreev (back_prog_argv);
+	back_prog_watcher_event_id = g_child_watch_add (pid, 
+							back_prog_on_exit,
+							NULL);
+	back_prog_pid = pid;
+}
+
+/*
+ * This function stops the background program if it is runnning,
+ * and removes any associated timer or watcher.
+ */
+static void 
+back_prog_stop (void)
+{
+	if (back_prog_timeout_event_id != -1) {
+		GSource *source = g_main_context_find_source_by_id
+					(NULL, back_prog_timeout_event_id);
+		if (source != NULL)
+			g_source_destroy (source);
+			
+		back_prog_timeout_event_id = -1;
+	}
+	
+	if (back_prog_watcher_event_id != -1) {
+		GSource *source = g_main_context_find_source_by_id
+					(NULL, back_prog_watcher_event_id);
+		if (source != NULL)
+			g_source_destroy (source);
+			
+		back_prog_watcher_event_id = -1;
+	}
+	
+	if (back_prog_pid != -1) {		
+		if (kill (back_prog_pid, SIGTERM) == 0) {
+			waitpid (back_prog_pid, NULL, 0);
+		}
+
+		back_prog_pid = -1;
+	}
+}
+
+
 /*
  * Timed Login: Timer
  */
@@ -267,7 +440,7 @@
 {
 	if (GdmFlexiReapDelayMinutes > 0 &&
 	    ((time (NULL) - last_reap_delay) / 60) > GdmFlexiReapDelayMinutes) {
-		gdm_kill_thingies ();
+		back_prog_stop ();
 		_exit (DISPLAY_REMANAGE);
 	}
 	return TRUE;
@@ -317,7 +490,7 @@
 static void
 gdm_login_done (int sig)
 {
-    gdm_kill_thingies ();
+    back_prog_stop ();
     _exit (EXIT_SUCCESS);
 }
 
@@ -517,7 +690,7 @@
 
     return g_string_free (str, FALSE);
 }
-
+#if 0
 static pid_t
 gdm_run_command (const char *command)
 {
@@ -566,7 +739,7 @@
 
 	return pid;
 }
-
+#endif
 static void
 gdm_run_gdmconfig (GtkWidget *w, gpointer data)
 {
@@ -586,7 +759,7 @@
 			     _("_Reboot"), GTK_STOCK_CANCEL)) {
 		closelog();
 
-		gdm_kill_thingies ();
+		back_prog_stop ();
 		_exit (DISPLAY_REBOOT);
 	}
 }
@@ -600,7 +773,7 @@
 			     _("Shut _Down"), GTK_STOCK_CANCEL)) {
 		closelog();
 
-		gdm_kill_thingies ();
+		back_prog_stop ();
 		_exit (DISPLAY_HALT);
 	}
 }
@@ -610,7 +783,7 @@
 {
 	closelog();
 
-	gdm_kill_thingies ();
+	back_prog_stop ();
 	_exit (DISPLAY_RUN_CHOOSER);
 }
 
@@ -690,6 +863,8 @@
     }
     GdmBackgroundProg = ve_config_get_string (config, GDM_KEY_BACKGROUNDPROG);
     GdmRunBackgroundProgAlways = ve_config_get_bool (config, GDM_KEY_RUNBACKGROUNDPROGALWAYS);
+    GdmBackgroundProgInitDelay = ve_config_get_int (config, GDM_KEY_BACKGROUNDPROGINITDELAY);
+    GdmBackgroundProgNextDelay = ve_config_get_int (config, GDM_KEY_BACKGROUNDPROGNEXTDELAY);
     GdmBackgroundImage = ve_config_get_string (config, GDM_KEY_BACKGROUNDIMAGE);
     GdmBackgroundColor = ve_config_get_string (config, GDM_KEY_BACKGROUNDCOLOR);
     GdmBackgroundType = ve_config_get_int (config, GDM_KEY_BACKGROUNDTYPE);
@@ -2169,7 +2344,7 @@
 		messages_to_give = FALSE;
 	}
 
-	gdm_kill_thingies ();
+	back_prog_stop ();
 
 	gdk_flush ();
 
@@ -2266,7 +2441,7 @@
 
 	gdm_wm_save_wm_order ();
 
-	gdm_kill_thingies ();
+	back_prog_stop ();
 	gdk_flush ();
 
 	_exit (EXIT_SUCCESS);
@@ -3608,22 +3783,6 @@
 	}
 }
 
-
-/* Load the background stuff, the image and program */
-static void
-run_backgrounds (void)
-{
-	setup_background ();
-
-	/* Launch a background program if one exists */
-	if ((GdmBackgroundType == GDM_BACKGROUND_NONE ||
-	     GdmRunBackgroundProgAlways) &&
-	    ! ve_string_empty (GdmBackgroundProg)) {
-		backgroundpid = gdm_run_command (GdmBackgroundProg);
-		g_atexit (gdm_kill_thingies);
-	}
-}
-
 enum {
 	RESPONSE_RESTART,
 	RESPONSE_REBOOT,
@@ -3659,7 +3818,7 @@
 
 		gdm_wm_save_wm_order ();
 
-		gdm_kill_thingies ();
+		back_prog_stop ();
 		_exit (DISPLAY_RESTARTGREETER);
 		return TRUE;
 	}
@@ -3679,18 +3838,9 @@
 		GdmBackgroundScaleToFit = ve_config_get_bool (config, GDM_KEY_BACKGROUNDSCALETOFIT);
 		GdmBackgroundRemoteOnlyColor = ve_config_get_bool (config, GDM_KEY_BACKGROUNDREMOTEONLYCOLOR);
 
-		if (GdmBackgroundType != GDM_BACKGROUND_NONE &&
-		    ! GdmRunBackgroundProgAlways)
-			gdm_kill_thingies ();
-
+		back_prog_stop ();
 		setup_background ();
-
-		/* Launch a background program if one exists */
-		if ((GdmBackgroundType == GDM_BACKGROUND_NONE ||
-		     GdmRunBackgroundProgAlways) &&
-		    ! ve_string_empty (GdmBackgroundProg)) {
-			backgroundpid = gdm_run_command (GdmBackgroundProg);
-		}
+		back_prog_launch_after_timeout (GdmBackgroundProgNextDelay);
 	}
 
 	GdmSoundProgram = ve_config_get_string (config, GDM_KEY_SOUND_PROGRAM);
@@ -3980,14 +4130,19 @@
     if G_UNLIKELY (sigprocmask (SIG_UNBLOCK, &mask, NULL) == -1) 
 	gdm_common_abort (_("Could not set signal mask!"));
 
-    /* ignore SIGCHLD */
-    sigemptyset (&mask);
+    /* ignore SIGCHLD. FIX ME. */
+    /*sigemptyset (&mask);
     sigaddset (&mask, SIGCHLD);
     
     if G_UNLIKELY (sigprocmask (SIG_BLOCK, &mask, NULL) == -1) 
 	gdm_common_abort (_("Could not set signal mask!"));
-
-    run_backgrounds ();
+    */	
+    /* Load the background stuff, the image and program */
+    setup_background ();
+    
+    /* Launch a background program if one exists */
+    g_atexit (back_prog_stop);
+    back_prog_launch_after_timeout (GdmBackgroundProgInitDelay);
 
     if G_LIKELY ( ! DOING_GDM_DEVELOPMENT) {
 	    ctrlch = g_io_channel_unix_new (STDIN_FILENO);
@@ -4179,7 +4334,7 @@
 
     gtk_main ();
 
-    gdm_kill_thingies ();
+    back_prog_stop ();
 
     return EXIT_SUCCESS;
 }
--- old/gdm.h	2005-03-23 00:20:05.000000000 -0500
+++ new/gdm.h	2005-03-23 00:19:42.000000000 -0500
@@ -241,6 +241,8 @@
 #define GDM_KEY_XINERAMASCREEN "greeter/XineramaScreen=0"
 #define GDM_KEY_BACKGROUNDPROG "greeter/BackgroundProgram="
 #define GDM_KEY_RUNBACKGROUNDPROGALWAYS "greeter/RunBackgroundProgramAlways=false"
+#define GDM_KEY_BACKGROUNDPROGINITDELAY "greeter/BackgroundProgramInitialDelay=30"
+#define GDM_KEY_BACKGROUNDPROGNEXTDELAY "greeter/BackgroundProgramNextDelay=30"
 #define GDM_KEY_BACKGROUNDIMAGE "greeter/BackgroundImage="
 #define GDM_KEY_BACKGROUNDCOLOR "greeter/BackgroundColor=#76848F"
 #define GDM_KEY_BACKGROUNDTYPE "greeter/BackgroundType=2"


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]