Fast User Switching gdm patch



This patch to gdm emulates Windows XP's "Fast User Switching", which i 
call "Multiple Desktops".  Here's an example case:
user 1 logs in-> assigned to vt 7
user 1 runs "gdmflexiserver", starts new xnest on vt 8
user 2 logs in on vt 8
user 2 runs "gdmflexiserver", starts new xnest on vt 9
user 1 logs in-> screen switches to vt 7 , gdmlogin keeps running
user 1 runs "gdmflexiserver", vt switches to vt 9 revealing gdm login 
screen


I'd appreciate any feedback.  The patch is against -11 from aug 30
don't know about cvs.

cat FastUserSwitching.diff | patch -p0 

from the gdm-...-11 directory you want to patch...



-- 
  \---  ===  E D  P A L M E R
  \ |   |_| 
  /---  |    http://ed.freeshell.org
diff -C 3 -r daemon/gdm.c ../gdm-2.4.0.11NEWEST/daemon/gdm.c
*** daemon/gdm.c	Tue Aug 27 21:03:35 2002
--- ../gdm-2.4.0.11NEWEST/daemon/gdm.c	Fri Sep 13 15:49:56 2002
***************
*** 64,69 ****
--- 64,74 ----
  static void gdm_safe_restart (void);
  static void gdm_restart_now (void);
  
+ #ifdef __linux__
+ GdmDisplay * login_what_display (char *login);
+ #endif
+ 
+ 
  /* Global vars */
  GSList *displays = NULL;	/* List of displays managed */
  GSList *xservers = NULL;	/* List of x server definitions */
***************
*** 161,167 ****
  gchar *GdmXnest = NULL;
  int GdmFirstVT = 7;
  gboolean GdmVTAllocation = TRUE;
! 
  
  /* set in the main function */
  char **stored_argv = NULL;
--- 166,172 ----
  gchar *GdmXnest = NULL;
  int GdmFirstVT = 7;
  gboolean GdmVTAllocation = TRUE;
! gboolean GdmMultipleDesktops = TRUE;
  
  /* set in the main function */
  char **stored_argv = NULL;
***************
*** 315,320 ****
--- 320,328 ----
      GdmVTAllocation = gnome_config_get_bool (GDM_KEY_VTALLOCATION);    
  
      GdmDebug = gnome_config_get_bool (GDM_KEY_DEBUG);
+     
+     GdmMultipleDesktops = gnome_config_get_bool (GDM_KEY_MULTIPLE_DESKTOPS);
+ 
  
      gnome_config_pop_prefix();
  
***************
*** 2765,2768 ****
--- 2773,2830 ----
  	}
  }
  
+ 
+ 
+ #ifdef __linux__
+ /* returns 
+    GdmDisplay * pointing to a display with a currently running greeter 
+    or NULL
+ */
+ GdmDisplay *
+ find_available_greeter ()
+ {
+         GSList *li;
+ 	
+ 	for (li = displays; li !=NULL; li=li->next) {
+ 		GdmDisplay *disp = li->data;
+ 		if (disp == NULL) 
+ 			gdm_error("find_avialable_greeter: null display in displays list");
+ 		if ( ( disp->login == NULL || !strlen(disp->login) )
+ 		       && disp->vt > 0 )
+ 			return disp;
+         }
+ 	
+         return NULL;            
+ }
+ 
+ /* what display is this login logged in on (if any) else NULL */
+ GdmDisplay *
+ login_what_display (char *login)
+ {
+         GSList *li;
+ 	
+         if (login==NULL) {
+ 		gdm_error("login_what_display: attempted to pass null login");
+ 		return NULL;
+         }
+ 	
+         for (li = displays; li !=NULL; li=li->next) {
+                 GdmDisplay *disp = li->data;
+                 if (disp==NULL) {
+ 			gdm_debug("login_what_display: disp is NULL");
+                 } else if (disp->login==NULL) {
+ 			/* do nothing */
+ 		       
+                 } else if (strcmp(login, disp->login) == 0) {
+ 			gdm_debug("login_what_display: (%s) is on vt %d", login, disp->vt);
+ 			return disp;
+                 }
+         }
+         return NULL;            
+ }
+ 
+ #endif
+ 
+ 
+ 
  /* EOF */
diff -C 3 -r daemon/gdm.h ../gdm-2.4.0.11NEWEST/daemon/gdm.h
*** daemon/gdm.h	Fri Aug 23 13:02:11 2002
--- ../gdm-2.4.0.11NEWEST/daemon/gdm.h	Fri Sep 13 14:32:43 2002
***************
*** 151,156 ****
--- 151,158 ----
  #define GDM_KEY_UAUTHFILE "daemon/UserAuthFile=.Xauthority"
  #define GDM_KEY_USER "daemon/User=gdm"
  
+ #define GDM_KEY_MULTIPLE_DESKTOPS "daemon/MultipleDesktops=true"
+ 
  /* This defaults to true for backward compatibility,
   * it will not actually do timed login since the TimedLogin defaults
   * to nothing */
***************
*** 623,628 ****
--- 625,635 ----
  					  * from a local display we started */
  };
  
+ #ifdef __linux__
+ GdmDisplay * login_what_display (char *login);
+ GdmDisplay * find_available_greeter (void);
+ #endif
+ 
  #endif /* GDM_H */
  
  /* EOF */
diff -C 3 -r daemon/misc.c ../gdm-2.4.0.11NEWEST/daemon/misc.c
*** daemon/misc.c	Fri Aug 30 14:51:06 2002
--- ../gdm-2.4.0.11NEWEST/daemon/misc.c	Fri Sep 13 14:16:09 2002
***************
*** 143,149 ****
      va_start (args, format);
      s = g_strdup_vprintf (format, args);
      va_end (args);
! 
      do_syslog (LOG_INFO, s);
      
      g_free (s);
--- 143,149 ----
      va_start (args, format);
      s = g_strdup_vprintf (format, args);
      va_end (args);
!     
      do_syslog (LOG_INFO, s);
      
      g_free (s);
***************
*** 187,202 ****
  {
      va_list args;
      char *s;
! 
      if ( ! GdmDebug) 
! 	return;
  
      va_start (args, format);
      s = g_strdup_vprintf (format, args);
      va_end (args);
  
      do_syslog (LOG_ERR, s);	/* Maybe should be LOG_DEBUG, but then normally
! 				 * you wouldn't get it in the log.  ??? */
      
      g_free (s);
  }
--- 187,202 ----
  {
      va_list args;
      char *s;
!     
      if ( ! GdmDebug) 
! 	    return;
  
      va_start (args, format);
      s = g_strdup_vprintf (format, args);
      va_end (args);
  
      do_syslog (LOG_ERR, s);	/* Maybe should be LOG_DEBUG, but then normally
! 				/* you wouldn't get it in the log.  ??? */
      
      g_free (s);
  }
diff -C 3 -r daemon/server.c ../gdm-2.4.0.11NEWEST/daemon/server.c
*** daemon/server.c	Fri Aug 30 15:18:51 2002
--- ../gdm-2.4.0.11NEWEST/daemon/server.c	Fri Sep 13 14:16:09 2002
***************
*** 340,372 ****
  	return FALSE;
  }
  
  static int
  display_vt (GdmDisplay *disp)
  {
  	char *logname = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
  	FILE *fp;
  	char buf[256];
  
  	fp = fopen (logname, "r");
  	g_free (logname);
! 
! 	if (fp == NULL)
! 		return FALSE;
! 
  	while (fgets (buf, sizeof (buf), fp) != NULL) {
! 		int vt;
! 		/* Note: this is probably XFree86 specific, and perhaps even
! 		 * version 3 specific (I don't have xfree v4 to test this),
! 		 * of course additions are welcome to make this more robust */
! 		if (sscanf (buf, "(using VT number %d)", &vt) == 1) {
  			fclose (fp);
  			return vt;
  		}
  	}
  	fclose (fp);
  	return -1;
  }
  
  static void
  check_child_status (void)
  {
--- 340,421 ----
  	return FALSE;
  }
  
+ /* Read a fp looking for vt info, returning it if necessary 
+  * Add additional */
+ static int
+ parse_vt (char *buf) {
+ 	
+ 	int vt;
+ 	
+ 	if ( (sscanf (buf, "(using VT number %d)", &vt) == 1) || 
+ 	     /* Note: this is probably XFree86 specific, and perhaps even
+ 	      * version 3 specific (I don't have xfree v4 to test this),
+ 	      * of course additions are welcome to make this more robust */
+ 	     /* I noticed it in 4.0 as well */
+ 	     (sscanf (buf, "Using vt %d", &vt) == 1) || 
+ 	     /* this is what works for some 4.2's... namely Mandrake 9.0 Beta 4 
+ 	      *	however, Redhat 7.2's 4.2 server doesn't put this info in the gdm info file */   
+ 	     (sscanf (buf, "(--) using VT number %d", &vt) == 1) /* from 4.2 Xserver log */
+ 		)
+     return vt;
+ 
+   else return -1;
+ 
+ }
+ 
+ /* Read the gdm log file looking for the vt, continuing to the XServer log if necessary
+  * Returns vt, or -1 on failure */
  static int
  display_vt (GdmDisplay *disp)
  {
  	char *logname = g_strconcat (GdmLogDir, "/", d->name, ".log", NULL);
  	FILE *fp;
  	char buf[256];
+ 	
+ 	char xserver_logfile[256];
+ 	xserver_logfile[0]=0;
  
  	fp = fopen (logname, "r");
  	g_free (logname);
! 		
  	while (fgets (buf, sizeof (buf), fp) != NULL) {
! 		int vt=-1;
! 		
! 		sscanf (buf, "(==) Log file: \"%[^\"]\"", xserver_logfile);
! 		
! 		if ( (vt=parse_vt(buf))!=-1  ){
  			fclose (fp);
+ 			gdm_debug("display_vt: found vt=%d in gdm log", vt);
  			return vt;
  		}
  	}
  	fclose (fp);
+ 	
+ 	if (strlen (xserver_logfile)) {
+ 		/* we didn't find a vt listed in the gdm log, lets try the XServer log itself */
+ 		gdm_debug("display_vt: continuing on to XServer log [%s]", xserver_logfile);
+ 		fp = fopen (xserver_logfile, "r");
+ 		
+ 		if (fp == NULL)
+ 			return -1;
+ 		
+ 		while (fgets (buf, sizeof (buf), fp) != NULL) {
+ 			int vt=-1;	    
+ 			if ( (vt=parse_vt(buf))!=-1  ){
+ 				fclose (fp);
+ 				gdm_debug("display_vt: found vt=%d in XServer log", vt);
+ 				return vt;
+ 			}
+ 		}
+ 		fclose (fp);		
+ 	}
+ 	
+ 	gdm_debug("display_vt: unable to set the vt");
  	return -1;
  }
  
+ 
+ 
  static void
  check_child_status (void)
  {
diff -C 3 -r daemon/slave.c ../gdm-2.4.0.11NEWEST/daemon/slave.c
*** daemon/slave.c	Fri Aug 30 14:53:43 2002
--- ../gdm-2.4.0.11NEWEST/daemon/slave.c	Fri Sep 13 15:52:07 2002
***************
*** 63,68 ****
--- 63,73 ----
  #include "choose.h"
  #include "errorgui.h"
  
+ #ifdef __linux__
+ #include <sys/ioctl.h>
+ #include <linux/vt.h>
+ #endif
+ 
  /* Some per slave globals */
  static GdmDisplay *d;
  static gchar *login = NULL;
***************
*** 135,141 ****
  extern gboolean GdmAllowRemoteRoot;
  extern gchar *GdmGlobalFaceDir;
  extern gboolean GdmDebug;
! 
  
  /* Local prototypes */
  static gint     gdm_slave_xerror_handler (Display *disp, XErrorEvent *evt);
--- 140,146 ----
  extern gboolean GdmAllowRemoteRoot;
  extern gchar *GdmGlobalFaceDir;
  extern gboolean GdmDebug;
! extern gboolean GdmMultipleDesktops;
  
  /* Local prototypes */
  static gint     gdm_slave_xerror_handler (Display *disp, XErrorEvent *evt);
***************
*** 162,167 ****
--- 167,176 ----
  static void	create_temp_auth_file (void);
  static void	set_xnest_parent_stuff (void);
  
+ #ifdef __linux__
+ static int      vt_switch (int switchto);
+ #endif
+ 
  /* Yay thread unsafety */
  static gboolean x_error_occured = FALSE;
  static gboolean gdm_got_ack = FALSE;
***************
*** 249,258 ****
--- 258,283 ----
  	time_t first_time;
  	int death_count;
  	struct sigaction alrm, term, child, usr2;
+ #ifdef __linux__
+ 	GdmDisplay *tmp_disp = find_available_greeter ();
+ #endif
  
  	if (!display)
  		return;
  
+ #ifdef __linux__
+ 	/* if display is xnest, and we have an available greeter just go there and kill this slave */
+ 	if (GdmMultipleDesktops && 
+ 	    display->type == TYPE_FLEXI && tmp_disp != NULL) {
+ 		gdm_debug("gdm_slave_start: will not start new greeter.  switching to %d.", tmp_disp->vt);
+ 		
+ 		if (vt_switch (tmp_disp->vt)) { 
+ 			display->login=NULL;
+ 			return;
+ 		} 
+ 	} else { gdm_debug("gdm_slave_start: no available greeter.  starting new one of type [%d]", display->type ); }
+ #endif       
+ 
  	gdm_debug ("gdm_slave_start: Starting slave process for %s", display->name);
  	if (display->type == TYPE_XDMCP &&
  	    GdmPingInterval > 0) {
***************
*** 324,332 ****
  		gdm_debug ("gdm_slave_start: Loop Thingie");
  		gdm_slave_run (display);
  
! 		/* remote and flexi only run once */
  		if (display->type != TYPE_LOCAL)
  			break;
  
  		the_time = time (NULL);
  
--- 349,376 ----
  		gdm_debug ("gdm_slave_start: Loop Thingie");
  		gdm_slave_run (display);
  
! 
! #ifdef __linux__
! 		if (display->type != TYPE_LOCAL && 
! 		    display->type != TYPE_FLEXI )
! 			break;
!                 /* remote display always exits here */
! 		
! 		/* we will continue if there are no other available greeters on other displays */
! 		d=find_available_greeter();
! 		if (GdmMultipleDesktops && display->type != TYPE_LOCAL && d != NULL && d->vt > 0 && d->vt != display->vt) {
! 			/* switch to that display then break out of here */
! 			if ( vt_switch(d->vt) ) {
! 				gdm_debug("gdm_slave_start: another suitable greeter was found.  exiting");
! 				break;
! 			}
! 		}
! #else
! 		/* otherwise remote and flexi only run once */
  		if (display->type != TYPE_LOCAL)
  			break;
+ #endif
+ 
  
  		the_time = time (NULL);
  
***************
*** 676,681 ****
--- 720,728 ----
  	    gdm_first_login = FALSE;
  
      do {
+ #ifdef __linux__ 
+ 	    GdmDisplay *disp;
+ #endif
  	    check_notifies_now ();
  
  	    if ( ! greet) {
***************
*** 685,690 ****
--- 732,742 ----
  	    }
  
  	    gdm_slave_wait_for_login (); /* wait for a password */
+ #ifdef __linux__	    
+ 	    disp=login_what_display(login);
+ 	    if (disp==NULL) gdm_debug("disp is NULL");
+ 	    else gdm_debug("disp on %d", disp->vt);
+ #endif
  
  	    d->logged_in = TRUE;
  	    gdm_slave_send_num (GDM_SOP_LOGGED_IN, TRUE);
***************
*** 697,703 ****
  						   ParsedTimedLogin);
  			    gdm_slave_session_start ();
  		    }
! 	    } else {
  		    gdm_slave_send_string (GDM_SOP_LOGIN, login);
  		    gdm_slave_session_start ();
  	    }
--- 749,768 ----
  						   ParsedTimedLogin);
  			    gdm_slave_session_start ();
  		    }
! 	    } 
! 
! #ifdef __linux__
! 	    else if ( GdmMultipleDesktops && disp!=NULL && disp->vt>=0 &&
! 		      vt_switch(disp->vt) ){ 
! 			    /* this user is already logged in! (and has a valid vt we switched to) */
! 			    gdm_debug("found login for '%s' on vt=%d",
! 				      login, disp->vt);
! 			    gdm_slave_greeter_ctl_no_ret (GDM_ENABLE, "");
! 			    gdm_slave_greeter_ctl_no_ret (GDM_RESETOK, "");	    
! 		    }
! #endif
! 	    /* fall through to normal login */
! 	    else {
  		    gdm_slave_send_string (GDM_SOP_LOGIN, login);
  		    gdm_slave_session_start ();
  	    }
***************
*** 3809,3812 ****
--- 3874,3896 ----
  	return TRUE;
  }
  
+ 
+ #ifdef __linux__
+ /* switch to vt "switchto" 
+    there is a linux utility "chvt", should that be used instead? */
+ static int 
+ vt_switch (int switchto) 
+ {
+ 	int fd;
+    
+ 	fd = open("/dev/console", O_RDWR);
+ 
+ 	if (ioctl(fd, VT_ACTIVATE, switchto)) {
+ 		gdm_error("vt_switch: unable to switch to vt %d", switchto);
+ 		return (0);
+ 	}
+ 	return 1;
+ }
+ #endif
+ 
  /* EOF */


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