diff src/video/fbcon/SDL_fbevents.c @ 1780:7a36f01acf71

Fixed bug #49 Added support for non-blocking VT switching on the framebuffer console.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 08 May 2006 05:33:02 +0000
parents e28233f37f8c
children d8030f368b84
line wrap: on
line diff
--- a/src/video/fbcon/SDL_fbevents.c	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fbevents.c	Mon May 08 05:33:02 2006 +0000
@@ -209,6 +209,8 @@
 			SDL_SetError("Unable to set keyboard in graphics mode");
 			return(-1);
 		}
+		/* Prevent switching the virtual terminal */
+		ioctl(keyboard_fd, VT_LOCKSWITCH, 1);
 	}
 	return(keyboard_fd);
 }
@@ -222,6 +224,7 @@
 		saved_kbd_mode = -1;
 
 		/* Head back over to the original virtual terminal */
+		ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1);
 		if ( saved_vt > 0 ) {
 			ioctl(keyboard_fd, VT_ACTIVATE, saved_vt);
 		}
@@ -456,7 +459,7 @@
 			{0xFF}
 	*/
 	Uint8 set_imps2[] = {0xf3, 200, 0xf3, 100, 0xf3, 80};
-	Uint8 reset = 0xff;
+	/*Uint8 reset = 0xff;*/
 	fd_set fdset;
 	struct timeval tv;
 	int retval = 0;
@@ -916,65 +919,60 @@
 	return;
 }
 
-/* Handle switching to another VC, returns when our VC is back.
-   This isn't necessarily the best solution.  For SDL 1.3 we need
-   a way of notifying the application when we lose access to the
-   video hardware and when we regain it.
- */
+/* Handle switching to another VC, returns when our VC is back */
+static void switch_vt_prep(_THIS)
+{
+	SDL_Surface *screen = SDL_VideoSurface;
+
+	SDL_PrivateAppActive(0, (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS));
+
+	/* Save the contents of the screen, and go to text mode */
+	wait_idle(this);
+	screen_arealen = ((screen->h + (2*this->offset_y)) * screen->pitch);
+	screen_contents = (Uint8 *)SDL_malloc(screen_arealen);
+	if ( screen_contents ) {
+		SDL_memcpy(screen_contents, screen->pixels, screen_arealen);
+	}
+	FB_SavePaletteTo(this, 256, screen_palette);
+	ioctl(console_fd, FBIOGET_VSCREENINFO, &screen_vinfo);
+	ioctl(keyboard_fd, KDSETMODE, KD_TEXT);
+	ioctl(keyboard_fd, VT_UNLOCKSWITCH, 1);
+}
+static void switch_vt_done(_THIS)
+{
+	SDL_Surface *screen = SDL_VideoSurface;
+
+	/* Restore graphics mode and the contents of the screen */
+	ioctl(keyboard_fd, VT_LOCKSWITCH, 1);
+	ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS);
+	ioctl(console_fd, FBIOPUT_VSCREENINFO, &screen_vinfo);
+	FB_RestorePaletteFrom(this, 256, screen_palette);
+	if ( screen_contents ) {
+		SDL_memcpy(screen->pixels, screen_contents, screen_arealen);
+		SDL_free(screen_contents);
+		screen_contents = NULL;
+	}
+
+	SDL_PrivateAppActive(1, (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS));
+}
 static void switch_vt(_THIS, unsigned short which)
 {
-	struct fb_var_screeninfo vinfo;
 	struct vt_stat vtstate;
-	unsigned short v_active;
-	__u16 saved_pal[3*256];
-	SDL_Surface *screen;
-	Uint32 screen_arealen;
-	Uint8 *screen_contents = NULL;
 
 	/* Figure out whether or not we're switching to a new console */
 	if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) < 0) ||
 	     (which == vtstate.v_active) ) {
 		return;
 	}
-	v_active = vtstate.v_active;
-
-	/* Save the contents of the screen, and go to text mode */
-	SDL_mutexP(hw_lock);
-	wait_idle(this);
-	screen = SDL_VideoSurface;
-	if ( !SDL_ShadowSurface ) {
-		screen_arealen = (screen->h*screen->pitch);
-		screen_contents = (Uint8 *)SDL_malloc(screen_arealen);
-		if ( screen_contents ) {
-			SDL_memcpy(screen_contents, (Uint8 *)screen->pixels + screen->offset, screen_arealen);
-		}
-	}
-	FB_SavePaletteTo(this, 256, saved_pal);
-	ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo);
-	ioctl(keyboard_fd, KDSETMODE, KD_TEXT);
 
 	/* New console, switch to it */
+	SDL_mutexP(hw_lock);
+	switch_vt_prep(this);
 	if ( ioctl(keyboard_fd, VT_ACTIVATE, which) == 0 ) {
-		/* Wait for our console to be activated again */
 		ioctl(keyboard_fd, VT_WAITACTIVE, which);
-		while ( ioctl(keyboard_fd, VT_WAITACTIVE, v_active) < 0 ) {
-			if ( (errno != EINTR) && (errno != EAGAIN) ) {
-				/* Unknown VT error - cancel this */
-				break;
-			}
-			SDL_Delay(500);
-		}
-	}
-
-	/* Restore graphics mode and the contents of the screen */
-	ioctl(keyboard_fd, KDSETMODE, KD_GRAPHICS);
-	ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo);
-	FB_RestorePaletteFrom(this, 256, saved_pal);
-	if ( screen_contents ) {
-		SDL_memcpy((Uint8 *)screen->pixels + screen->offset, screen_contents, screen_arealen);
-		SDL_free(screen_contents);
+		switched_away = 1;
 	} else {
-		SDL_UpdateRect(screen, 0, 0, 0, 0);
+		switch_vt_done(this);
 	}
 	SDL_mutexV(hw_lock);
 }
@@ -1032,6 +1030,18 @@
 	static struct timeval zero;
 
 	do {
+		if ( switched_away ) {
+			struct vt_stat vtstate;
+
+			SDL_mutexP(hw_lock);
+			if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) == 0) &&
+			     vtstate.v_active == current_vt ) {
+				switched_away = 0;
+				switch_vt_done(this);
+			}
+			SDL_mutexV(hw_lock);
+		}
+
 		posted = 0;
 
 		FD_ZERO(&fdset);