src/video/bwindow/SDL_sysvideo.cc
author Sam Lantinga <slouken@libsdl.org>
Mon, 20 Feb 2012 23:51:08 -0500
branchSDL-1.2
changeset 6297 c787fb1b5699
parent 4888 46fb637777ed
permissions -rw-r--r--
Fixed bug 1426 - SDL_SemWaitTimeout returns -1 and sets error instead of SDL_MUTEX_TIMEDOUT on time out

deraj 2012-02-19 19:01:08 PST

Fix to treat ETIMEDOUT as a time out instead of an error (and update the test)
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2012 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* BWindow based framebuffer implementation */
    25 
    26 #include <unistd.h>
    27 
    28 #include "SDL_BWin.h"
    29 #include "SDL_timer.h"
    30 
    31 extern "C" {
    32 
    33 #include "../SDL_sysvideo.h"
    34 #include "../../events/SDL_events_c.h"
    35 #include "SDL_sysevents_c.h"
    36 #include "SDL_sysmouse_c.h"
    37 #include "SDL_syswm_c.h"
    38 #include "SDL_lowvideo.h"
    39 #include "../SDL_yuvfuncs.h"
    40 #include "SDL_sysyuv.h"
    41 #include "../blank_cursor.h"
    42 
    43 #define BEOS_HIDDEN_SIZE	32	/* starting hidden window size */
    44 
    45 /* Initialization/Query functions */
    46 static int BE_VideoInit(_THIS, SDL_PixelFormat *vformat);
    47 static SDL_Rect **BE_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
    48 static SDL_Surface *BE_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
    49 static void BE_UpdateMouse(_THIS);
    50 static int BE_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
    51 static void BE_VideoQuit(_THIS);
    52 
    53 /* Hardware surface functions */
    54 static int BE_AllocHWSurface(_THIS, SDL_Surface *surface);
    55 static int BE_LockHWSurface(_THIS, SDL_Surface *surface);
    56 static void BE_UnlockHWSurface(_THIS, SDL_Surface *surface);
    57 static void BE_FreeHWSurface(_THIS, SDL_Surface *surface);
    58 
    59 static int BE_ToggleFullScreen(_THIS, int fullscreen);
    60 
    61 /* OpenGL functions */
    62 #if SDL_VIDEO_OPENGL
    63 static int BE_GL_LoadLibrary(_THIS, const char *path);
    64 static void* BE_GL_GetProcAddress(_THIS, const char *proc);
    65 static int BE_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value);
    66 static int BE_GL_MakeCurrent(_THIS);
    67 static void BE_GL_SwapBuffers(_THIS);
    68 #endif
    69 
    70 /* FB driver bootstrap functions */
    71 
    72 static int BE_Available(void)
    73 {
    74 	return(1);
    75 }
    76 
    77 static void BE_DeleteDevice(SDL_VideoDevice *device)
    78 {
    79 	SDL_free(device->hidden);
    80 	SDL_free(device);
    81 }
    82 
    83 static SDL_VideoDevice *BE_CreateDevice(int devindex)
    84 {
    85 	SDL_VideoDevice *device;
    86 
    87 	/* Initialize all variables that we clean on shutdown */
    88 	device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
    89 	if ( device ) {
    90 		SDL_memset(device, 0, (sizeof *device));
    91 		device->hidden = (struct SDL_PrivateVideoData *)
    92 				SDL_malloc((sizeof *device->hidden));
    93 	}
    94 	if ( (device == NULL) || (device->hidden == NULL) ) {
    95 		SDL_OutOfMemory();
    96 		if ( device ) {
    97 			SDL_free(device);
    98 		}
    99 		return(0);
   100 	}
   101 	SDL_memset(device->hidden, 0, (sizeof *device->hidden));
   102 
   103 	/* Set the function pointers */
   104 	/* Initialization/Query functions */
   105 	device->VideoInit = BE_VideoInit;
   106 	device->ListModes = BE_ListModes;
   107 	device->SetVideoMode = BE_SetVideoMode;
   108 	device->ToggleFullScreen = BE_ToggleFullScreen;
   109 	device->UpdateMouse = BE_UpdateMouse;
   110 	device->CreateYUVOverlay = BE_CreateYUVOverlay;
   111 	device->SetColors = BE_SetColors;
   112 	device->UpdateRects = NULL;
   113 	device->VideoQuit = BE_VideoQuit;
   114 	/* Hardware acceleration functions */
   115 	device->AllocHWSurface = BE_AllocHWSurface;
   116 	device->CheckHWBlit = NULL;
   117 	device->FillHWRect = NULL;
   118 	device->SetHWColorKey = NULL;
   119 	device->SetHWAlpha = NULL;
   120 	device->LockHWSurface = BE_LockHWSurface;
   121 	device->UnlockHWSurface = BE_UnlockHWSurface;
   122 	device->FlipHWSurface = NULL;
   123 	device->FreeHWSurface = BE_FreeHWSurface;
   124 	/* Gamma support */
   125 #if SDL_VIDEO_OPENGL
   126 	/* OpenGL support */
   127 	device->GL_LoadLibrary = BE_GL_LoadLibrary;
   128 	device->GL_GetProcAddress = BE_GL_GetProcAddress;
   129 	device->GL_GetAttribute = BE_GL_GetAttribute;
   130 	device->GL_MakeCurrent = BE_GL_MakeCurrent;
   131 	device->GL_SwapBuffers = BE_GL_SwapBuffers;
   132 #endif
   133 	/* Window manager functions */
   134 	device->SetCaption = BE_SetWMCaption;
   135 	device->SetIcon = NULL;
   136 	device->IconifyWindow = BE_IconifyWindow;
   137 	device->GrabInput = BE_GrabInput;
   138 	device->GetWMInfo = BE_GetWMInfo;
   139 	/* Cursor manager functions */
   140 	device->FreeWMCursor = BE_FreeWMCursor;
   141 	device->CreateWMCursor = BE_CreateWMCursor;
   142 	device->ShowWMCursor = BE_ShowWMCursor;
   143 	device->WarpWMCursor = BE_WarpWMCursor;
   144 	device->MoveWMCursor = NULL;
   145 	device->CheckMouseMode = BE_CheckMouseMode;
   146 	/* Event manager functions */
   147 	device->InitOSKeymap = BE_InitOSKeymap;
   148 	device->PumpEvents = BE_PumpEvents;
   149 
   150 	device->free = BE_DeleteDevice;
   151 
   152 	/* Set the driver flags */
   153 	device->handles_any_size = 1;
   154 	
   155 	return device;
   156 }
   157 
   158 VideoBootStrap BWINDOW_bootstrap = {
   159 	"bwindow", "BDirectWindow graphics",
   160 	BE_Available, BE_CreateDevice
   161 };
   162 
   163 static inline int ColorSpaceToBitsPerPixel(uint32 colorspace)
   164 {
   165 	int bitsperpixel;
   166 
   167 	bitsperpixel = 0;
   168 	switch (colorspace) {
   169 	    case B_CMAP8:
   170 		bitsperpixel = 8;
   171 		break;
   172 	    case B_RGB15:
   173 	    case B_RGBA15:
   174 	    case B_RGB15_BIG:
   175 	    case B_RGBA15_BIG:
   176 		bitsperpixel = 15;
   177 		break;
   178 	    case B_RGB16:
   179 	    case B_RGB16_BIG:
   180 		bitsperpixel = 16;
   181 		break;
   182 	    case B_RGB32:
   183 	    case B_RGBA32:
   184 	    case B_RGB32_BIG:
   185 	    case B_RGBA32_BIG:
   186 		bitsperpixel = 32;
   187 		break;
   188 	    default:
   189 		break;
   190 	}
   191 	return(bitsperpixel);
   192 }
   193 
   194 /* Function to sort the display_list in bscreen */
   195 static int CompareModes(const void *A, const void *B)
   196 {
   197 	const display_mode *a = (display_mode *)A;
   198 	const display_mode *b = (display_mode *)B;
   199 
   200 	if ( a->space == b->space ) {
   201 		return((b->virtual_width*b->virtual_height)-
   202 		       (a->virtual_width*a->virtual_height));
   203 	} else {
   204 		return(ColorSpaceToBitsPerPixel(b->space)-
   205 		       ColorSpaceToBitsPerPixel(a->space));
   206 	}
   207 }
   208 
   209 /* Yes, this isn't the fastest it could be, but it works nicely */
   210 static int BE_AddMode(_THIS, int index, unsigned int w, unsigned int h)
   211 {
   212 	SDL_Rect *mode;
   213 	int i;
   214 	int next_mode;
   215 
   216 	/* Check to see if we already have this mode */
   217 	if ( SDL_nummodes[index] > 0 ) {
   218 		for ( i=SDL_nummodes[index]-1; i >= 0; --i ) {
   219 			mode = SDL_modelist[index][i];
   220 			if ( (mode->w == w) && (mode->h == h) ) {
   221 #ifdef BWINDOW_DEBUG
   222 				fprintf(stderr, "We already have mode %dx%d at %d bytes per pixel\n", w, h, index+1);
   223 #endif
   224 				return(0);
   225 			}
   226 		}
   227 	}
   228 
   229 	/* Set up the new video mode rectangle */
   230 	mode = (SDL_Rect *)SDL_malloc(sizeof *mode);
   231 	if ( mode == NULL ) {
   232 		SDL_OutOfMemory();
   233 		return(-1);
   234 	}
   235 	mode->x = 0;
   236 	mode->y = 0;
   237 	mode->w = w;
   238 	mode->h = h;
   239 #ifdef BWINDOW_DEBUG
   240 	fprintf(stderr, "Adding mode %dx%d at %d bytes per pixel\n", w, h, index+1);
   241 #endif
   242 
   243 	/* Allocate the new list of modes, and fill in the new mode */
   244 	next_mode = SDL_nummodes[index];
   245 	SDL_modelist[index] = (SDL_Rect **)
   246 	       SDL_realloc(SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
   247 	if ( SDL_modelist[index] == NULL ) {
   248 		SDL_OutOfMemory();
   249 		SDL_nummodes[index] = 0;
   250 		SDL_free(mode);
   251 		return(-1);
   252 	}
   253 	SDL_modelist[index][next_mode] = mode;
   254 	SDL_modelist[index][next_mode+1] = NULL;
   255 	SDL_nummodes[index]++;
   256 
   257 	return(0);
   258 }
   259 
   260 int BE_VideoInit(_THIS, SDL_PixelFormat *vformat)
   261 {
   262 	display_mode *modes;
   263 	uint32 i, nmodes;
   264 	int bpp;
   265 	BRect bounds;
   266 
   267 	/* Initialize the Be Application for appserver interaction */
   268 	if ( SDL_InitBeApp() < 0 ) {
   269 		return(-1);
   270 	}
   271 
   272 	/* It is important that this be created after SDL_InitBeApp() */
   273 	BScreen bscreen;
   274 
   275 	/* Save the current display mode */
   276 	bscreen.GetMode(&saved_mode);
   277 	_this->info.current_w = saved_mode.virtual_width;
   278 	_this->info.current_h = saved_mode.virtual_height;
   279 
   280 	/* Determine the screen depth */
   281 	vformat->BitsPerPixel = ColorSpaceToBitsPerPixel(bscreen.ColorSpace());
   282 	if ( vformat->BitsPerPixel == 0 ) {
   283 		SDL_SetError("Unknown BScreen colorspace: 0x%x",
   284 						bscreen.ColorSpace());
   285 		return(-1);
   286 	}
   287 
   288 	/* Get the video modes we can switch to in fullscreen mode */
   289 	bscreen.GetModeList(&modes, &nmodes);
   290 	SDL_qsort(modes, nmodes, sizeof *modes, CompareModes);
   291 	for ( i=0; i<nmodes; ++i ) {
   292 		bpp = ColorSpaceToBitsPerPixel(modes[i].space);
   293 		//if ( bpp != 0 ) { // There are bugs in changing colorspace
   294 		if ( modes[i].space == saved_mode.space ) {
   295 			BE_AddMode(_this, ((bpp+7)/8)-1,
   296 				modes[i].virtual_width,
   297 				modes[i].virtual_height);
   298 		}
   299 	}
   300 
   301 	/* Create the window and view */
   302 	bounds.top = 0; bounds.left = 0;
   303 	bounds.right = BEOS_HIDDEN_SIZE;
   304 	bounds.bottom = BEOS_HIDDEN_SIZE;
   305 	SDL_Win = new SDL_BWin(bounds);
   306 
   307 #if SDL_VIDEO_OPENGL
   308 	/* testgl application doesn't load library, just tries to load symbols */
   309 	/* is it correct? if so we have to load library here */
   310 	BE_GL_LoadLibrary(_this, NULL);
   311 #endif
   312 
   313 	/* Create the clear cursor */
   314 	SDL_BlankCursor = BE_CreateWMCursor(_this, blank_cdata, blank_cmask,
   315 			BLANK_CWIDTH, BLANK_CHEIGHT, BLANK_CHOTX, BLANK_CHOTY);
   316 
   317 	/* Fill in some window manager capabilities */
   318 	_this->info.wm_available = 1;
   319 
   320 	/* We're done! */
   321 	return(0);
   322 }
   323 
   324 /* We support any dimension at our bit-depth */
   325 SDL_Rect **BE_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   326 {
   327 	SDL_Rect **modes;
   328 
   329 	modes = ((SDL_Rect **)0);
   330 	if ( (flags & SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
   331 		modes = SDL_modelist[((format->BitsPerPixel+7)/8)-1];
   332 	} else {
   333 		if ( format->BitsPerPixel ==
   334 			_this->screen->format->BitsPerPixel ) {
   335 			modes = ((SDL_Rect **)-1);
   336 		}
   337 	}
   338 	return(modes);
   339 }
   340 
   341 /* Various screen update functions available */
   342 static void BE_NormalUpdate(_THIS, int numrects, SDL_Rect *rects);
   343 
   344 
   345 /* Find the closest display mode for fullscreen */
   346 static bool BE_FindClosestFSMode(_THIS, int width, int height, int bpp,
   347 					 display_mode *mode)
   348 {
   349 	BScreen bscreen;
   350 	uint32 i, nmodes;
   351 	SDL_Rect **modes;
   352 	display_mode *dmodes;
   353 	display_mode current;
   354 	float current_refresh;
   355 	bscreen.GetMode(&current);
   356 	current_refresh = (1000 * current.timing.pixel_clock) / 
   357 	                  (current.timing.h_total * current.timing.v_total);
   358 
   359 	modes = SDL_modelist[((bpp+7)/8)-1];
   360 	
   361 	// find end of list (lowest-resolution mode; modes are ordered
   362 	// highest-to-lowest).
   363 	i = 0; while(modes[i]) i++;
   364 	if (!i) return false;		// what? no modes at all?
   365 	
   366 	// find first mode with resolution >= requested in both dimensions
   367 	for (--i; i >= 0; --i)
   368 	{
   369 		if (modes[i]->w >= width && modes[i]->h >= height)
   370 			break;
   371 	}
   372 	
   373 	// unable to find any mode with that high a resolution!
   374 	if (i < 0)
   375 		return false;
   376 	
   377 	width = modes[i]->w;
   378 	height = modes[i]->h;
   379 
   380 	bscreen.GetModeList(&dmodes, &nmodes);
   381 	for ( i = 0; i < nmodes; ++i ) {
   382 		if ( (bpp == ColorSpaceToBitsPerPixel(dmodes[i].space)) &&
   383 		     (width == dmodes[i].virtual_width) &&
   384 		     (height == dmodes[i].virtual_height) ) {
   385 			break;
   386 		}
   387 	}
   388 	if ( i != nmodes ) {
   389 		*mode = dmodes[i];
   390 		if ((mode->virtual_width <= current.virtual_width) &&
   391 		    (mode->virtual_height <= current.virtual_height)) {
   392 			float new_refresh = (1000 * mode->timing.pixel_clock) /
   393 			                    (mode->timing.h_total * mode->timing.v_total);
   394 			if (new_refresh < current_refresh) {
   395 				mode->timing.pixel_clock = (uint32)((mode->timing.h_total * mode->timing.v_total)
   396 				                                    * current_refresh / 1000);
   397 			}
   398 		}
   399 		return true;
   400 	} else {
   401 		return false;
   402 	}	
   403 }
   404 
   405 static int BE_SetFullScreen(_THIS, SDL_Surface *screen, int fullscreen)
   406 {
   407 	// printf("SetFullScreen(%d)\n", fullscreen);
   408 	BScreen bscreen;
   409 
   410 	// SetFullSscreen() does not work as expected if called in a window
   411 	// that was never shown. This is probably a bug in the Haiku Game Kit that needs
   412 	// to be investigated.	
   413 	if (SDL_Win->Lock()) {
   414 		// Show our window.
   415 		SDL_Win->Show();
   416 	}	
   417 	
   418 	if (SDL_Win->IsLocked()) {
   419 		// Unlock the window if it was locked. This is needed as only the
   420 		// first call to Show() unlocks the looper. All other calls to it
   421 		// will not.
   422 		SDL_Win->Unlock();
   423 	}
   424 
   425 	int width = screen->w;
   426 	int height = screen->h;
   427 	
   428 	if (fullscreen) {
   429 		// Set resolution to the closest available one that matches the
   430 		// current SDL resolution.
   431 		display_mode mode;
   432 		bscreen.GetMode(&mode);
   433 
   434 		int bpp = screen->format->BitsPerPixel;
   435 		if (bpp != ColorSpaceToBitsPerPixel(mode.space) ||
   436 			width != mode.virtual_width || height != mode.virtual_height) {
   437 			if(BE_FindClosestFSMode(_this, width, height, bpp, &mode)) {
   438 				bscreen.SetMode(&mode);
   439 			} else {
   440 				// printf("Could not set new mode.\n");
   441 				return(0);
   442 			}			
   443 		}
   444 	} else {
   445 		// Reset to the previous known resolution as we are now in window
   446 		// mode.
   447 		bscreen.SetMode(&saved_mode);	
   448 	}
   449 	
   450 	// Effectivelly set/reset full screen mode. If we are already in
   451 	// full screen mode, we reset back to windowed mode first so the
   452 	// window can resize when going fullscreen.
   453 	// if (fullscreen)
   454 		// printf("Going fullscreen\n");
   455 	// else
   456 		// printf("Going windowed\n"); 
   457 	SDL_Win->SetFullScreen(fullscreen);
   458 	
   459 	// Calculate offsets for centering the window (in window mode) and for
   460 	// dentering the bitmap (in full screen mode).
   461 	BRect bounds = bscreen.Frame();
   462 	bounds.PrintToStream();
   463 	int32 cx = (bounds.IntegerWidth() - width)/2;
   464 	int32 cy = (bounds.IntegerHeight() - height)/2;
   465 	
   466 	// printf ("cx = %d, cy = %d\n", cx, cy);
   467 	if (!SDL_Win->IsFullScreen()) {
   468 		// printf("Doing not fullscreen stuff.\n");
   469 		// We are not in full screen mode, so we want to change the window
   470 		// size to match the resolution in SDL.
   471 		SDL_Win->ResizeTo(width, height);
   472 		
   473 		// And also center the window and reset the drawing offset.
   474 		SDL_Win->MoveTo(cx, cy);
   475 		SDL_Win->SetXYOffset(0, 0);
   476 	} else {
   477 		// printf("Doing fullscreen stuff.");
   478 		// Center the bitmap whenever we are in full screen mode.
   479 		SDL_Win->SetXYOffset(cx, cy);
   480 	}
   481 	
   482 	// Set relevant internal SDL screen flags.
   483 	if (SDL_Win->IsFullScreen()) {
   484 		screen->flags |= SDL_FULLSCREEN;
   485 	} else {
   486 		screen->flags &= ~SDL_FULLSCREEN; 
   487 	}
   488 
   489 	return(1);
   490 }
   491 
   492 static int BE_ToggleFullScreen(_THIS, int fullscreen)
   493 {
   494 	return BE_SetFullScreen(_this, _this->screen, fullscreen);
   495 }
   496 
   497 /* FIXME: check return values and cleanup here */
   498 SDL_Surface *BE_SetVideoMode(_THIS, SDL_Surface *current,
   499 				int width, int height, int bpp, Uint32 flags)
   500 {
   501 	BScreen bscreen;
   502 	BBitmap *bbitmap;
   503 	BRect bounds;
   504 	Uint32 gl_flags = 0;
   505 
   506 	/* Only RGB works on r5 currently */
   507 	gl_flags = BGL_RGB;
   508 	if (_this->gl_config.double_buffer)
   509 		gl_flags |= BGL_DOUBLE;
   510 	else
   511 		gl_flags |= BGL_SINGLE;
   512 	if (_this->gl_config.alpha_size > 0 || bpp == 32)
   513 		gl_flags |= BGL_ALPHA;
   514 	if (_this->gl_config.depth_size > 0)
   515 		gl_flags |= BGL_DEPTH;
   516 	if (_this->gl_config.stencil_size > 0)
   517 		gl_flags |= BGL_STENCIL;
   518 	if (_this->gl_config.accum_red_size > 0
   519 		|| _this->gl_config.accum_green_size > 0
   520 		|| _this->gl_config.accum_blue_size > 0
   521 		|| _this->gl_config.accum_alpha_size > 0)
   522 		gl_flags |= BGL_ACCUM;
   523 
   524 	/* Create the view for this window, using found flags */
   525 	if ( SDL_Win->CreateView(flags, gl_flags) < 0 ) {
   526 		return(NULL);
   527 	}
   528 
   529 	current->flags = 0;		/* Clear flags */
   530 	current->w = width;
   531 	current->h = height;
   532 	SDL_Win->SetType(B_TITLED_WINDOW);
   533 	if ( flags & SDL_NOFRAME ) {
   534 		current->flags |= SDL_NOFRAME;
   535 		SDL_Win->SetLook(B_NO_BORDER_WINDOW_LOOK);
   536 	} else {
   537 		if ( (flags & SDL_RESIZABLE) && !(flags & SDL_OPENGL) )  {
   538 			current->flags |= SDL_RESIZABLE;
   539 			/* We don't want opaque resizing (TM). :-) */
   540 			SDL_Win->SetFlags(B_OUTLINE_RESIZE);
   541 		} else {
   542 			SDL_Win->SetFlags(B_NOT_RESIZABLE|B_NOT_ZOOMABLE);
   543 		}
   544 	}
   545 
   546 	if ( flags & SDL_OPENGL ) {
   547 		current->flags |= SDL_OPENGL;
   548 		current->pitch = 0;
   549 		current->pixels = NULL;
   550 		_this->UpdateRects = NULL;
   551 	} else {
   552 		/* Create the BBitmap framebuffer */
   553 		bounds.top = 0; bounds.left = 0;
   554 		bounds.right = width-1;
   555 		bounds.bottom = height-1;
   556 		bbitmap = new BBitmap(bounds, bscreen.ColorSpace());
   557 		if ( ! bbitmap->IsValid() ) {
   558 			SDL_SetError("Couldn't create screen bitmap");
   559 			delete bbitmap;
   560 			return(NULL);
   561 		}
   562 		current->pitch = bbitmap->BytesPerRow();
   563 		current->pixels = (void *)bbitmap->Bits();
   564 		SDL_Win->SetBitmap(bbitmap);
   565 		_this->UpdateRects = BE_NormalUpdate;
   566 	}
   567 
   568 	/* Set the correct fullscreen mode */
   569 	BE_SetFullScreen(_this, current, flags & SDL_FULLSCREEN ? 1 : 0);
   570 
   571 	/* We're done */
   572 	return(current);
   573 }
   574 
   575 /* Update the current mouse state and position */
   576 void BE_UpdateMouse(_THIS)
   577 {
   578 	BPoint point;
   579 	uint32 buttons;
   580 
   581 	if ( SDL_Win->Lock() ) {
   582 		/* Get new input state, if still active */
   583 		if ( SDL_Win->IsActive() ) {
   584 			(SDL_Win->View())->GetMouse(&point, &buttons, true);
   585 		} else {
   586 			point.x = -1;
   587 			point.y = -1;
   588 		}
   589 		SDL_Win->Unlock();
   590 
   591 		if ( (point.x >= 0) && (point.x < SDL_VideoSurface->w) &&
   592 		     (point.y >= 0) && (point.y < SDL_VideoSurface->h) ) {
   593 			SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   594 			SDL_PrivateMouseMotion(0, 0,
   595 					(Sint16)point.x, (Sint16)point.y);
   596 		} else {
   597 			SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   598 		}
   599 	}
   600 }
   601 
   602 /* We don't actually allow hardware surfaces other than the main one */
   603 static int BE_AllocHWSurface(_THIS, SDL_Surface *surface)
   604 {
   605 	return(-1);
   606 }
   607 static void BE_FreeHWSurface(_THIS, SDL_Surface *surface)
   608 {
   609 	return;
   610 }
   611 static int BE_LockHWSurface(_THIS, SDL_Surface *surface)
   612 {
   613 	return(0);
   614 }
   615 static void BE_UnlockHWSurface(_THIS, SDL_Surface *surface)
   616 {
   617 	return;
   618 }
   619 
   620 static void BE_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
   621 {
   622 	if ( SDL_Win->BeginDraw() ) {
   623 		int i;
   624 
   625 		for ( i=0; i<numrects; ++i ) {
   626 			BRect rect;
   627 
   628 			rect.top = rects[i].y;
   629 			rect.left = rects[i].x;
   630 			rect.bottom = rect.top+rects[i].h-1;
   631 			rect.right = rect.left+rects[i].w-1;
   632 			SDL_Win->DrawAsync(rect);
   633 		}
   634 		SDL_Win->EndDraw();
   635 	}
   636 }
   637 
   638 #if SDL_VIDEO_OPENGL
   639 /* Passing a NULL path means load pointers from the application */
   640 int BE_GL_LoadLibrary(_THIS, const char *path)
   641 {
   642 	if (path == NULL) {
   643 		if (_this->gl_config.dll_handle == NULL) {
   644 			image_info info;
   645 			int32 cookie = 0;
   646 			while (get_next_image_info(0,&cookie,&info) == B_OK) {
   647 				void *location = NULL;
   648 #ifdef __HAIKU__
   649 				if (get_image_symbol(info.id,"glBegin",B_SYMBOL_TYPE_ANY,&location) == B_OK) { // This is how it actually works in Haiku
   650 #else
   651 				if (get_image_symbol((image_id)cookie,"glBegin",B_SYMBOL_TYPE_ANY,&location) == B_OK) { // I don't know if that *did* work in BeOS
   652 #endif
   653 					_this->gl_config.dll_handle = (void*)info.id;
   654 					_this->gl_config.driver_loaded = 1;
   655 					SDL_strlcpy(_this->gl_config.driver_path, "libGL.so", SDL_arraysize(_this->gl_config.driver_path));
   656 				}
   657 			}
   658 		}
   659 	} else {
   660 		/*
   661 			FIXME None of BeOS libGL.so implementations have exported functions 
   662 			to load BGLView, which should be reloaded from new lib.
   663 			So for now just "load" linked libGL.so :(
   664 		*/
   665 		if (_this->gl_config.dll_handle == NULL) {
   666 			return BE_GL_LoadLibrary(_this, NULL);
   667 		}
   668 
   669 		/* Unload old first */
   670 		/*if (_this->gl_config.dll_handle != NULL) {*/
   671 			/* Do not try to unload application itself (if LoadLibrary was called before with NULL ;) */
   672 		/*	image_info info;
   673 			if (get_image_info((image_id)_this->gl_config.dll_handle, &info) == B_OK) {
   674 				if (info.type != B_APP_IMAGE) {
   675 					unload_add_on((image_id)_this->gl_config.dll_handle);
   676 				}
   677 			}
   678 			
   679 		}
   680 
   681 		if ((_this->gl_config.dll_handle = (void*)load_add_on(path)) != (void*)B_ERROR) {
   682 			_this->gl_config.driver_loaded = 1;
   683 			SDL_strlcpy(_this->gl_config.driver_path, path, SDL_arraysize(_this->gl_config.driver_path));
   684 		}*/
   685 	}
   686 
   687 	if (_this->gl_config.dll_handle != NULL) {
   688 		return 0;
   689 	} else {
   690 		_this->gl_config.dll_handle = NULL;
   691 		_this->gl_config.driver_loaded = 0;
   692 		*_this->gl_config.driver_path = '\0';
   693 		return -1;
   694 	}
   695 }
   696 
   697 void* BE_GL_GetProcAddress(_THIS, const char *proc)
   698 {
   699 	if (_this->gl_config.dll_handle != NULL) {
   700 		void *location = NULL;
   701 		status_t err;
   702 		if ((err = get_image_symbol((image_id)_this->gl_config.dll_handle, proc, B_SYMBOL_TYPE_ANY, &location)) == B_OK) {
   703 			return location;
   704 		} else {
   705 			SDL_SetError("Couldn't find OpenGL symbol");
   706 			return NULL;
   707 		}
   708 	} else {
   709 		SDL_SetError("OpenGL library not loaded");
   710 		return NULL;
   711 	}
   712 }
   713 
   714 int BE_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value)
   715 {
   716 	/*
   717 		FIXME? Right now BE_GL_GetAttribute shouldn't be called between glBegin() and glEnd() - it doesn't use "cached" values
   718 	*/
   719 	switch (attrib)
   720     {
   721 		case SDL_GL_RED_SIZE:
   722 			glGetIntegerv(GL_RED_BITS, (GLint*)value);
   723 			break;
   724 		case SDL_GL_GREEN_SIZE:
   725 			glGetIntegerv(GL_GREEN_BITS, (GLint*)value);
   726 			break;
   727 		case SDL_GL_BLUE_SIZE:
   728 			glGetIntegerv(GL_BLUE_BITS, (GLint*)value);
   729 			break;
   730 		case SDL_GL_ALPHA_SIZE:
   731 			glGetIntegerv(GL_ALPHA_BITS, (GLint*)value);
   732 			break;
   733 		case SDL_GL_DOUBLEBUFFER:
   734 			glGetBooleanv(GL_DOUBLEBUFFER, (GLboolean*)value);
   735 			break;
   736 		case SDL_GL_BUFFER_SIZE:
   737 			int v;
   738 			glGetIntegerv(GL_RED_BITS, (GLint*)&v);
   739 			*value = v;
   740 			glGetIntegerv(GL_GREEN_BITS, (GLint*)&v);
   741 			*value += v;
   742 			glGetIntegerv(GL_BLUE_BITS, (GLint*)&v);
   743 			*value += v;
   744 			glGetIntegerv(GL_ALPHA_BITS, (GLint*)&v);
   745 			*value += v;
   746 			break;
   747 		case SDL_GL_DEPTH_SIZE:
   748 			glGetIntegerv(GL_DEPTH_BITS, (GLint*)value); /* Mesa creates 16 only? r5 always 32 */
   749 			break;
   750 		case SDL_GL_STENCIL_SIZE:
   751 			glGetIntegerv(GL_STENCIL_BITS, (GLint*)value);
   752 			break;
   753 		case SDL_GL_ACCUM_RED_SIZE:
   754 			glGetIntegerv(GL_ACCUM_RED_BITS, (GLint*)value);
   755 			break;
   756 		case SDL_GL_ACCUM_GREEN_SIZE:
   757 			glGetIntegerv(GL_ACCUM_GREEN_BITS, (GLint*)value);
   758 			break;
   759 		case SDL_GL_ACCUM_BLUE_SIZE:
   760 			glGetIntegerv(GL_ACCUM_BLUE_BITS, (GLint*)value);
   761 			break;
   762 		case SDL_GL_ACCUM_ALPHA_SIZE:
   763 			glGetIntegerv(GL_ACCUM_ALPHA_BITS, (GLint*)value);
   764 			break;
   765 		case SDL_GL_STEREO:
   766 		case SDL_GL_MULTISAMPLEBUFFERS:
   767 		case SDL_GL_MULTISAMPLESAMPLES:
   768 		default:
   769 			*value=0;
   770 			return(-1);
   771 	}
   772 	return 0;
   773 }
   774 
   775 int BE_GL_MakeCurrent(_THIS)
   776 {
   777 	/* FIXME: should we glview->unlock and then glview->lock()? */
   778 	return 0;
   779 }
   780 
   781 void BE_GL_SwapBuffers(_THIS)
   782 {
   783 	SDL_Win->SwapBuffers();
   784 }
   785 #endif
   786 
   787 /* Is the system palette settable? */
   788 int BE_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   789 {
   790 	int i;
   791 	SDL_Palette *palette;
   792 	const color_map *cmap = BScreen().ColorMap();
   793 
   794 	/* Get the screen colormap */
   795 	palette = _this->screen->format->palette;
   796 	for ( i=0; i<256; ++i ) {
   797 		palette->colors[i].r = cmap->color_list[i].red;
   798 		palette->colors[i].g = cmap->color_list[i].green;
   799 		palette->colors[i].b = cmap->color_list[i].blue;
   800 	}
   801 	return(0);
   802 }
   803 
   804 void BE_VideoQuit(_THIS)
   805 {
   806 	int i, j;
   807 
   808 	SDL_Win->Quit();
   809 	SDL_Win = NULL;
   810 
   811 	if ( SDL_BlankCursor != NULL ) {
   812 		BE_FreeWMCursor(_this, SDL_BlankCursor);
   813 		SDL_BlankCursor = NULL;
   814 	}
   815 	for ( i=0; i<NUM_MODELISTS; ++i ) {
   816 		if ( SDL_modelist[i] ) {
   817 			for ( j=0; SDL_modelist[i][j]; ++j ) {
   818 				SDL_free(SDL_modelist[i][j]);
   819 			}
   820 			SDL_free(SDL_modelist[i]);
   821 			SDL_modelist[i] = NULL;
   822 		}
   823 	}
   824 	/* Restore the original video mode */
   825 	if ( _this->screen ) {
   826 		if ( (_this->screen->flags&SDL_FULLSCREEN) == SDL_FULLSCREEN ) {
   827 			BScreen bscreen;
   828 			bscreen.SetMode(&saved_mode);
   829 		}
   830 		_this->screen->pixels = NULL;
   831 	}
   832 
   833 #if SDL_VIDEO_OPENGL
   834 	if (_this->gl_config.dll_handle != NULL)
   835 		unload_add_on((image_id)_this->gl_config.dll_handle);
   836 #endif
   837 
   838 	SDL_QuitBeApp();
   839 }
   840 
   841 }; /* Extern C */