Fixed bug #49
authorSam Lantinga <slouken@libsdl.org>
Mon, 08 May 2006 05:33:02 +0000
changeset 1780 7a36f01acf71
parent 1779 67fc81efcfc3
child 1781 d8030f368b84
Fixed bug #49 Added support for non-blocking VT switching on the framebuffer console.
src/video/fbcon/SDL_fb3dfx.c
src/video/fbcon/SDL_fbevents.c
src/video/fbcon/SDL_fbmatrox.c
src/video/fbcon/SDL_fbriva.c
src/video/fbcon/SDL_fbvideo.c
src/video/fbcon/SDL_fbvideo.h
--- a/src/video/fbcon/SDL_fb3dfx.c	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fb3dfx.c	Mon May 08 05:33:02 2006 +0000
@@ -57,6 +57,9 @@
 	int dstX, dstY;
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
@@ -102,6 +105,9 @@
 	Uint32 use_colorkey;
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
--- 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);
--- a/src/video/fbcon/SDL_fbmatrox.c	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fbmatrox.c	Mon May 08 05:33:02 2006 +0000
@@ -70,6 +70,9 @@
 	Uint32 fillop;
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
@@ -132,6 +135,9 @@
 	}
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
--- a/src/video/fbcon/SDL_fbriva.c	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fbriva.c	Mon May 08 05:33:02 2006 +0000
@@ -77,6 +77,9 @@
 	RivaBitmap *Bitmap = (RivaBitmap *)(mapped_io + BITMAP_OFFSET);
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
@@ -120,6 +123,9 @@
 	}
 
 	/* Don't blit to the display surface when switched away */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
 	if ( dst == this->screen ) {
 		SDL_mutexP(hw_lock);
 	}
--- a/src/video/fbcon/SDL_fbvideo.c	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fbvideo.c	Mon May 08 05:33:02 2006 +0000
@@ -1238,26 +1238,10 @@
 	surface->hwdata = NULL;
 }
 
-/* Routine to check to see if the frame buffer virtual terminal */
-/* is the current(active) one.  If it is not, result will cause */
-/* Lock to fail.  (would have waited forever, since the fbevent */
-/* keyboard handler maintains a lock when switched away from    */
-/* current) */
-static __inline__ int FB_IsFrameBufferActive(_THIS)
-{
-	struct vt_stat vtstate;
-	if ( (ioctl(keyboard_fd, VT_GETSTATE, &vtstate) < 0) ||
-	     (current_vt != vtstate.v_active) ) {
-		return 0;
-	}
-	return 1;
-}
-
-
 static int FB_LockHWSurface(_THIS, SDL_Surface *surface)
 {
-	if ( !FB_IsFrameBufferActive(this) ) {
-		return -1; /* fail locking. */
+	if ( switched_away ) {
+		return -2; /* no hardware access */
 	}
 	if ( surface == this->screen ) {
 		SDL_mutexP(hw_lock);
@@ -1293,6 +1277,10 @@
 
 static int FB_FlipHWSurface(_THIS, SDL_Surface *surface)
 {
+	if ( switched_away ) {
+		return -2; /* no hardware access */
+	}
+
 	/* Wait for vertical retrace and then flip display */
 	cache_vinfo.yoffset = flip_page*surface->h;
 	if ( FB_IsSurfaceBusy(this->screen) ) {
@@ -1333,6 +1321,10 @@
     Uint32 *src, *srcPtr;
     Uint8  *dst, *dstPtr;
 
+    if ( switched_away ) {
+        return; /* no hardware access */
+    }
+
     screen = this->screen;
     FBPitch = screen->w >> 3;
     SRCPitch = screen->pitch >> 2;
--- a/src/video/fbcon/SDL_fbvideo.h	Mon May 08 05:30:15 2006 +0000
+++ b/src/video/fbcon/SDL_fbvideo.h	Mon May 08 05:33:02 2006 +0000
@@ -85,6 +85,11 @@
 	int surfaces_memleft;
 
 	SDL_mutex *hw_lock;
+	int switched_away;
+	struct fb_var_screeninfo screen_vinfo;
+	Uint32 screen_arealen;
+	Uint8 *screen_contents;
+	__u16  screen_palette[3*256];
 
 	void (*wait_vbl)(_THIS);
 	void (*wait_idle)(_THIS);
@@ -117,6 +122,11 @@
 #define surfaces_memtotal	(this->hidden->surfaces_memtotal)
 #define surfaces_memleft	(this->hidden->surfaces_memleft)
 #define hw_lock			(this->hidden->hw_lock)
+#define switched_away		(this->hidden->switched_away)
+#define screen_vinfo		(this->hidden->screen_vinfo)
+#define screen_arealen		(this->hidden->screen_arealen)
+#define screen_contents		(this->hidden->screen_contents)
+#define screen_palette		(this->hidden->screen_palette)
 #define wait_vbl		(this->hidden->wait_vbl)
 #define wait_idle		(this->hidden->wait_idle)