Fixed bug #798 SDL-1.2
authorSam Lantinga <slouken@libsdl.org>
Sat, 10 Oct 2009 02:11:07 +0000
branchSDL-1.2
changeset 4287 0620847bf1a8
parent 4286 9ea4413f0a9e
child 4288 4ab46e81d08e
Fixed bug #798 kty@lavabit.com 2009-09-19 14:19:04 PDT The stable release of SDL 1.2.13 for BeOS/Haiku has a bug in BE_FindClosestFSMode that causes it to sometimes not select the best mode when going fullscreen. There are in fact two bugs in the implementation but I will not go into specifics because there is already a patch for it in the developer SVN 1.3. However I am still reporting it because I believe the following code is a better patch for the issue. The current implementation on SVN only works if it is able to find an exact match for the requested mode. However, by scanning from lowest-to-highest resolution instead of highest-to-lowest, one can find the best mode at all times
src/video/bwindow/SDL_BWin.h
src/video/bwindow/SDL_sysevents.cc
src/video/bwindow/SDL_sysvideo.cc
--- a/src/video/bwindow/SDL_BWin.h	Sat Oct 10 02:03:53 2009 +0000
+++ b/src/video/bwindow/SDL_BWin.h	Sat Oct 10 02:11:07 2009 +0000
@@ -267,6 +267,8 @@
 	}
 
 	virtual void DispatchMessage(BMessage *msg, BHandler *target);
+	
+	virtual void DirectConnected(direct_buffer_info *info);
 
 private:
 #if SDL_VIDEO_OPENGL
--- a/src/video/bwindow/SDL_sysevents.cc	Sat Oct 10 02:03:53 2009 +0000
+++ b/src/video/bwindow/SDL_sysevents.cc	Sat Oct 10 02:11:07 2009 +0000
@@ -379,3 +379,20 @@
 	}
 	BDirectWindow::DispatchMessage(msg, target);
 }
+
+void SDL_BWin::DirectConnected(direct_buffer_info *info) {
+	switch (info->buffer_state & B_DIRECT_MODE_MASK) {
+		case B_DIRECT_START:
+		case B_DIRECT_MODIFY:
+			{
+				int32 width = info->window_bounds.right -
+					info->window_bounds.left + 1;
+				int32 height = info->window_bounds.bottom -
+					info->window_bounds.top + 1;
+				SDL_PrivateResize(width, height);
+				break;
+			}
+		default:
+			break;
+	}
+}
--- a/src/video/bwindow/SDL_sysvideo.cc	Sat Oct 10 02:03:53 2009 +0000
+++ b/src/video/bwindow/SDL_sysvideo.cc	Sat Oct 10 02:11:07 2009 +0000
@@ -57,7 +57,7 @@
 static void BE_FreeHWSurface(_THIS, SDL_Surface *surface);
 
 static int BE_ToggleFullScreen(_THIS, int fullscreen);
-SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display);
+static SDL_Overlay *BE_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display);
 
 /* OpenGL functions */
 #if SDL_VIDEO_OPENGL
@@ -358,16 +358,25 @@
 	                  (current.timing.h_total * current.timing.v_total);
 
 	modes = SDL_modelist[((bpp+7)/8)-1];
-	for ( i=0; modes[i] && (modes[i]->w > width) &&
-		      (modes[i]->h > height); ++i ) {
-		/* still looking */
+	
+	// find end of list (lowest-resolution mode; modes are ordered
+	// highest-to-lowest).
+	i = 0; while(modes[i]) i++;
+	if (!i) return false;		// what? no modes at all?
+	
+	// find first mode with resolution >= requested in both dimensions
+	for (--i; i >= 0; --i)
+	{
+		if (modes[i]->w >= width && modes[i]->h >= height)
+			break;
 	}
-	if ( ! modes[i] || (modes[i]->w < width) || (modes[i]->h < width) ) {
-		--i;	/* We went too far */
-	}
-
+	
+	// unable to find any mode with that high a resolution!
+	if (i < 0)
+		return false;
+	
 	width = modes[i]->w;
-	height = modes[i]->h;      
+	height = modes[i]->h;
 
 	bscreen.GetModeList(&dmodes, &nmodes);
 	for ( i = 0; i < nmodes; ++i ) {
@@ -396,88 +405,88 @@
 
 static int BE_SetFullScreen(_THIS, SDL_Surface *screen, int fullscreen)
 {
-	int was_fullscreen;
-	bool needs_unlock;
+	// printf("SetFullScreen(%d)\n", fullscreen);
 	BScreen bscreen;
-	BRect bounds;
-	display_mode mode;
-	int width, height, bpp;
-
-	/* Set the fullscreen mode */
-	was_fullscreen = SDL_Win->IsFullScreen();
-	SDL_Win->SetFullScreen(fullscreen);
-	fullscreen = SDL_Win->IsFullScreen();
-
-	width = screen->w;
-	height = screen->h;
 
-	/* Set the appropriate video mode */
-	if ( fullscreen ) {
-		bpp = screen->format->BitsPerPixel;
-		bscreen.GetMode(&mode);
-		if ( (bpp != ColorSpaceToBitsPerPixel(mode.space)) ||
-		     (width != mode.virtual_width) ||
-		     (height != mode.virtual_height)) {
-			if(BE_FindClosestFSMode(_this, width, height, bpp, &mode)) {
-				bscreen.SetMode(&mode);
-				/* This simply stops the next resize event from being
-				 * sent to the SDL handler.
-				 */
-				SDL_Win->InhibitResize();
-			} else {
-				fullscreen = 0;
-				SDL_Win->SetFullScreen(fullscreen);
-			}
-		}
-	}
-	if ( was_fullscreen && ! fullscreen ) {
-		bscreen.SetMode(&saved_mode);
+	// SetFullSscreen() does not work as expected if called in a window
+	// that was never shown. This is probably a bug in the Haiku Game Kit that needs
+	// to be investigated.	
+	if (SDL_Win->Lock()) {
+		// Show our window.
+		SDL_Win->Show();
+	}	
+	
+	if (SDL_Win->IsLocked()) {
+		// Unlock the window if it was locked. This is needed as only the
+		// first call to Show() unlocks the looper. All other calls to it
+		// will not.
+		SDL_Win->Unlock();
 	}
 
-	if ( SDL_Win->Lock() ) {
-		int cx, cy;
-		if ( SDL_Win->Shown() ) {
-			needs_unlock = 1;
-			SDL_Win->Hide();
-		} else {
-			needs_unlock = 0;
-		}
-		/* This resizes the window and view area, but inhibits resizing
-		 * of the BBitmap due to the InhibitResize call above. Thus the
-		 * bitmap (pixel data) never changes.
-		 */
-		SDL_Win->ResizeTo(width, height);
-		bounds = bscreen.Frame();
-		/* Calculate offsets - used either to center window
-		 * (windowed mode) or to set drawing offsets (fullscreen mode)
-		 */
-		cx = (bounds.IntegerWidth() - width)/2;
-		cy = (bounds.IntegerHeight() - height)/2;
+	int width = screen->w;
+	int height = screen->h;
+	
+	if (fullscreen) {
+		// Set resolution to the closest available one that matches the
+		// current SDL resolution.
+		display_mode mode;
+		bscreen.GetMode(&mode);
 
-		if ( fullscreen ) {
-			/* Set offset for drawing */
-			SDL_Win->SetXYOffset(cx, cy);
-		} else {
-			SDL_Win->SetXYOffset(0, 0);
-		}
-		if ( ! needs_unlock || was_fullscreen ) {
-			/* Center the window the first time */
-			SDL_Win->MoveTo(cx, cy);
+		int bpp = screen->format->BitsPerPixel;
+		if (bpp != ColorSpaceToBitsPerPixel(mode.space) ||
+			width != mode.virtual_width || height != mode.virtual_height) {
+			if(BE_FindClosestFSMode(_this, width, height, bpp, &mode)) {
+				bscreen.SetMode(&mode);
+			} else {
+				// printf("Could not set new mode.\n");
+				return(0);
+			}			
 		}
-		SDL_Win->Show();
+	} else {
+		// Reset to the previous known resolution as we are now in window
+		// mode.
+		bscreen.SetMode(&saved_mode);	
+	}
+	
+	// Effectivelly set/reset full screen mode. If we are already in
+	// full screen mode, we reset back to windowed mode first so the
+	// window can resize when going fullscreen.
+	// if (fullscreen)
+		// printf("Going fullscreen\n");
+	// else
+		// printf("Going windowed\n"); 
+	SDL_Win->SetFullScreen(fullscreen);
+	
+	// Calculate offsets for centering the window (in window mode) and for
+	// dentering the bitmap (in full screen mode).
+	BRect bounds = bscreen.Frame();
+	bounds.PrintToStream();
+	int32 cx = (bounds.IntegerWidth() - width)/2;
+	int32 cy = (bounds.IntegerHeight() - height)/2;
+	
+	// printf ("cx = %d, cy = %d\n", cx, cy);
+	if (!SDL_Win->IsFullScreen()) {
+		// printf("Doing not fullscreen stuff.\n");
+		// We are not in full screen mode, so we want to change the window
+		// size to match the resolution in SDL.
+		SDL_Win->ResizeTo(width, height);
 		
-		/* Unlock the window manually after the first Show() */
-		if ( needs_unlock ) {
-			SDL_Win->Unlock();
-		}
+		// And also center the window and reset the drawing offset.
+		SDL_Win->MoveTo(cx, cy);
+		SDL_Win->SetXYOffset(0, 0);
+	} else {
+		// printf("Doing fullscreen stuff.");
+		// Center the bitmap whenever we are in full screen mode.
+		SDL_Win->SetXYOffset(cx, cy);
 	}
-
-	/* Set the fullscreen flag in the screen surface */
-	if ( fullscreen ) {
+	
+	// Set relevant internal SDL screen flags.
+	if (SDL_Win->IsFullScreen()) {
 		screen->flags |= SDL_FULLSCREEN;
 	} else {
 		screen->flags &= ~SDL_FULLSCREEN; 
 	}
+
 	return(1);
 }