Conflicts:
	Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs
This commit is contained in:
Stefanos A 2013-10-03 15:11:59 +02:00
commit be7200d37e
2 changed files with 274 additions and 195 deletions

View file

@ -38,6 +38,8 @@ namespace OpenTK.Platform.SDL2
{ {
class Sdl2NativeWindow : INativeWindow, IInputDriver class Sdl2NativeWindow : INativeWindow, IInputDriver
{ {
readonly object sync = new object();
Sdl2WindowInfo window; Sdl2WindowInfo window;
uint window_id; uint window_id;
bool is_visible; bool is_visible;
@ -66,44 +68,44 @@ namespace OpenTK.Platform.SDL2
public Sdl2NativeWindow(int x, int y, int width, int height, public Sdl2NativeWindow(int x, int y, int width, int height,
string title, GameWindowFlags options, DisplayDevice device) string title, GameWindowFlags options, DisplayDevice device)
{ {
var bounds = device.Bounds; lock (sync)
var flags = TranslateFlags(options);
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL;
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE;
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN;
if ((flags & SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 ||
(flags & SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN) != 0)
window_state = WindowState.Fullscreen;
IntPtr handle;
lock (SDL.Sync)
{ {
handle = SDL.SDL_CreateWindow(title, bounds.Left + x, bounds.Top + y, width, height, flags); var bounds = device.Bounds;
var flags = TranslateFlags(options);
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL;
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE;
flags |= SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN;
if ((flags & SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 ||
(flags & SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN) != 0)
window_state = WindowState.Fullscreen;
IntPtr handle;
lock (SDL.Sync)
{
handle = SDL.SDL_CreateWindow(title, bounds.Left + x, bounds.Top + y, width, height, flags);
SDL.SDL_AddEventWatch(EventFilterDelegate, handle);
SDL.SDL_PumpEvents();
}
window = new Sdl2WindowInfo(handle, null);
window_id = SDL.SDL_GetWindowID(handle);
windows.Add(window_id, this);
window_title = title;
keyboard.Description = "Standard keyboard";
keyboard.NumberOfFunctionKeys = 12;
keyboard.NumberOfKeys = 101;
keyboard.NumberOfLeds = 3;
mouse.Description = "Standard mouse";
mouse.NumberOfButtons = 3;
mouse.NumberOfWheels = 1;
keyboards.Add(keyboard);
mice.Add(mouse);
exists = true;
} }
window = new Sdl2WindowInfo(handle, null);
window_id = SDL.SDL_GetWindowID(handle);
windows.Add(window_id, this);
window_title = title;
keyboard.Description = "Standard Windows keyboard";
keyboard.NumberOfFunctionKeys = 12;
keyboard.NumberOfKeys = 101;
keyboard.NumberOfLeds = 3;
mouse.Description = "Standard Windows mouse";
mouse.NumberOfButtons = 3;
mouse.NumberOfWheels = 1;
keyboards.Add(keyboard);
mice.Add(mouse);
lock (SDL.Sync)
{
SDL.SDL_AddEventWatch(EventFilterDelegate, handle);
}
exists = true;
} }
#region Private Members #region Private Members
@ -142,63 +144,57 @@ namespace OpenTK.Platform.SDL2
try try
{ {
Sdl2NativeWindow window = null;
SDL.SDL_Event ev = *(SDL.SDL_Event*)e;
Sdl2NativeWindow window = null; switch (ev.type)
SDL.SDL_Event ev = *(SDL.SDL_Event*)e; {
case SDL.SDL_EventType.SDL_WINDOWEVENT:
if (windows.TryGetValue(ev.window.windowID, out window))
{
ProcessWindowEvent(window, ev.window);
processed = true;
}
break;
switch (ev.type) case SDL.SDL_EventType.SDL_KEYDOWN:
{ case SDL.SDL_EventType.SDL_KEYUP:
case SDL.SDL_EventType.SDL_WINDOWEVENT: if (windows.TryGetValue(ev.key.windowID, out window))
if (windows.TryGetValue(ev.window.windowID, out window)) {
{ ProcessKeyEvent(window, ev);
ProcessWindowEvent(window, ev.window); processed = true;
processed = true; }
} break;
break;
case SDL.SDL_EventType.SDL_KEYDOWN: case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN:
case SDL.SDL_EventType.SDL_KEYUP: case SDL.SDL_EventType.SDL_MOUSEBUTTONUP:
if (windows.TryGetValue(ev.key.windowID, out window)) if (windows.TryGetValue(ev.button.windowID, out window))
{ {
ProcessKeyEvent(window, ev); ProcessButtonEvent(window, ev);
processed = true; processed = true;
} }
break; break;
case SDL.SDL_EventType.SDL_MOUSEBUTTONDOWN: case SDL.SDL_EventType.SDL_MOUSEMOTION:
case SDL.SDL_EventType.SDL_MOUSEBUTTONUP: if (windows.TryGetValue(ev.motion.windowID, out window))
if (windows.TryGetValue(ev.button.windowID, out window)) {
{ ProcessMotionEvent(window, ev);
ProcessButtonEvent(window, ev); processed = true;
processed = true; }
} break;
break;
case SDL.SDL_EventType.SDL_MOUSEMOTION: case SDL.SDL_EventType.SDL_MOUSEWHEEL:
if (windows.TryGetValue(ev.motion.windowID, out window)) if (windows.TryGetValue(ev.wheel.windowID, out window))
{ {
ProcessMotionEvent(window, ev); ProcessWheelEvent(window, ev);
processed = true; processed = true;
} }
break; break;
case SDL.SDL_EventType.SDL_MOUSEWHEEL: case SDL.SDL_EventType.SDL_QUIT:
if (windows.TryGetValue(ev.wheel.windowID, out window)) Debug.WriteLine("Sdl2 application quit");
{ break;
ProcessWheelEvent(window, ev); }
processed = true;
}
break;
case SDL.SDL_EventType.SDL_QUIT:
/*
if (windows.TryGetValue(ev.quit.windowID, out window))
{
}
*/
break;
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -271,7 +267,7 @@ namespace OpenTK.Platform.SDL2
if (!close_args.Cancel) if (!close_args.Cancel)
{ {
window.Closed(window, EventArgs.Empty); window.Closed(window, EventArgs.Empty);
window.DestroyWindow(); //window.DestroyWindow();
} }
break; break;
@ -347,12 +343,12 @@ namespace OpenTK.Platform.SDL2
{ {
lock (SDL.Sync) lock (SDL.Sync)
{ {
SDL.SDL_DestroyWindow(window.Handle);
SDL.SDL_DelEventWatch(EventFilterDelegate, window.Handle); SDL.SDL_DelEventWatch(EventFilterDelegate, window.Handle);
if (windows.ContainsKey(window_id)) if (windows.ContainsKey(window_id))
{ {
windows.Remove(window_id); windows.Remove(window_id);
} }
SDL.SDL_DestroyWindow(window.Handle);
} }
} }
@ -427,26 +423,29 @@ namespace OpenTK.Platform.SDL2
public void Close() public void Close()
{ {
if (Exists) lock (sync)
{ {
Debug.Print("SDL2 destroying window {0}", window.Handle); if (Exists)
SDL.SDL_Event e = new SDL.SDL_Event();
//e.type = SDL.SDL_EventType.SDL_QUIT;
e.type = SDL.SDL_EventType.SDL_WINDOWEVENT;
e.window.windowEvent = SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE;
e.window.windowID = window_id;
lock (SDL.Sync)
{ {
SDL.SDL_PushEvent(ref e); Debug.Print("SDL2 destroying window {0}", window.Handle);
SDL.SDL_Event e = new SDL.SDL_Event();
e.type = SDL.SDL_EventType.SDL_WINDOWEVENT;
e.window.windowEvent = SDL.SDL_WindowEventID.SDL_WINDOWEVENT_CLOSE;
e.window.windowID = window_id;
lock (SDL.Sync)
{
SDL.SDL_PushEvent(ref e);
}
} }
} }
} }
public void ProcessEvents() public void ProcessEvents()
{ {
if (Exists) lock (sync)
{ {
lock (SDL.Sync) if (Exists)
{ {
SDL.SDL_PumpEvents(); SDL.SDL_PumpEvents();
} }
@ -475,39 +474,45 @@ namespace OpenTK.Platform.SDL2
} }
set set
{ {
// Set the new icon, if any, or clear the current lock (sync)
// icon if null
if (value != null)
{ {
using (Bitmap bmp = value.ToBitmap()) if (Exists)
{ {
// Decode the icon into a SDL surface // Set the new icon, if any, or clear the current
var data = bmp.LockBits( // icon if null
new Rectangle(0, 0, value.Width, value.Height), if (value != null)
ImageLockMode.ReadWrite, {
PixelFormat.Format32bppArgb); using (Bitmap bmp = value.ToBitmap())
{
// Decode the icon into a SDL surface
var data = bmp.LockBits(
new Rectangle(0, 0, value.Width, value.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format32bppArgb);
IntPtr surface = SDL.SDL_CreateRGBSurfaceFrom( IntPtr surface = SDL.SDL_CreateRGBSurfaceFrom(
data.Scan0, data.Width, data.Height, 32, data.Stride, data.Scan0, data.Width, data.Height, 32, data.Stride,
0x00ff0000u, 0x0000ff00u, 0x000000ffu, 0xff000000u); 0x00ff0000u, 0x0000ff00u, 0x000000ffu, 0xff000000u);
// Update the window icon // Update the window icon
SDL.SDL_SetWindowIcon(window.Handle, surface); SDL.SDL_SetWindowIcon(window.Handle, surface);
// Free the SDL surface as it is no longer needed // Free the SDL surface as it is no longer needed
SDL.SDL_FreeSurface(surface); SDL.SDL_FreeSurface(surface);
bmp.UnlockBits(data); bmp.UnlockBits(data);
}
}
else
{
// Clear the window icon
SDL.SDL_SetWindowIcon(window.Handle, IntPtr.Zero);
}
icon = value;
IconChanged(this, EventArgs.Empty);
} }
} }
else
{
// Clear the window icon
SDL.SDL_SetWindowIcon(window.Handle, IntPtr.Zero);
}
icon = value;
IconChanged(this, EventArgs.Empty);
} }
} }
@ -515,12 +520,25 @@ namespace OpenTK.Platform.SDL2
{ {
get get
{ {
return SDL.SDL_GetWindowTitle(window.Handle); lock (sync)
{
if (Exists)
{
return SDL.SDL_GetWindowTitle(window.Handle);
}
return String.Empty;
}
} }
set set
{ {
SDL.SDL_SetWindowTitle(window.Handle, value); lock (sync)
window_title = value; {
if (Exists)
{
SDL.SDL_SetWindowTitle(window.Handle, value);
window_title = value;
}
}
} }
} }
@ -540,10 +558,16 @@ namespace OpenTK.Platform.SDL2
} }
set set
{ {
if (value) lock (sync)
SDL.SDL_ShowWindow(window.Handle); {
else if (Exists)
SDL.SDL_HideWindow(window.Handle); {
if (value)
SDL.SDL_ShowWindow(window.Handle);
else
SDL.SDL_HideWindow(window.Handle);
}
}
} }
} }
@ -571,46 +595,50 @@ namespace OpenTK.Platform.SDL2
} }
set set
{ {
if (WindowState == value) lock (sync)
{ {
return; if (Exists)
} {
if (WindowState != value)
// Set the new WindowState
switch (value)
{
case WindowState.Fullscreen:
RestoreWindow();
if (SDL.SDL_SetWindowFullscreen(window.Handle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) < 0)
{ {
if (SDL.SDL_SetWindowFullscreen(window.Handle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN) < 0) // Set the new WindowState
switch (value)
{ {
Debug.Print("SDL2 failed to enter fullscreen mode: {0}", SDL.SDL_GetError()); case WindowState.Fullscreen:
RestoreWindow();
if (SDL.SDL_SetWindowFullscreen(window.Handle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) < 0)
{
if (SDL.SDL_SetWindowFullscreen(window.Handle, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN) < 0)
{
Debug.Print("SDL2 failed to enter fullscreen mode: {0}", SDL.SDL_GetError());
}
}
SDL.SDL_RaiseWindow(window.Handle);
// There is no "fullscreen" message in the event loop
// so we have to mark that ourselves
window_state = WindowState.Fullscreen;
break;
case WindowState.Maximized:
RestoreWindow();
SDL.SDL_MaximizeWindow(window.Handle);
HideShowWindowHack();
break;
case WindowState.Minimized:
SDL.SDL_MinimizeWindow(window.Handle);
break;
case WindowState.Normal:
RestoreWindow();
break;
} }
if (!CursorVisible)
GrabCursor(true);
} }
SDL.SDL_RaiseWindow(window.Handle); }
// There is no "fullscreen" message in the event loop
// so we have to mark that ourselves
window_state = WindowState.Fullscreen;
break;
case WindowState.Maximized:
RestoreWindow();
SDL.SDL_MaximizeWindow(window.Handle);
HideShowWindowHack();
break;
case WindowState.Minimized:
SDL.SDL_MinimizeWindow(window.Handle);
break;
case WindowState.Normal:
RestoreWindow();
break;
} }
if (!CursorVisible)
GrabCursor(true);
} }
} }
@ -622,26 +650,36 @@ namespace OpenTK.Platform.SDL2
} }
set set
{ {
if (value != WindowBorder) if (WindowBorder != value)
{ {
switch (value) lock (sync)
{ {
case WindowBorder.Resizable: if (Exists)
SDL.SDL_SetWindowBordered(window.Handle, SDL.SDL_bool.SDL_TRUE); {
window_border = WindowBorder.Resizable;
break;
case WindowBorder.Hidden: switch (value)
SDL.SDL_SetWindowBordered(window.Handle, SDL.SDL_bool.SDL_FALSE); {
window_border = WindowBorder.Hidden; case WindowBorder.Resizable:
break; SDL.SDL_SetWindowBordered(window.Handle, SDL.SDL_bool.SDL_TRUE);
window_border = WindowBorder.Resizable;
break;
case WindowBorder.Fixed: case WindowBorder.Hidden:
Debug.WriteLine("SDL2 cannot change to fixed-size windows at runtime."); SDL.SDL_SetWindowBordered(window.Handle, SDL.SDL_bool.SDL_FALSE);
break; window_border = WindowBorder.Hidden;
break;
case WindowBorder.Fixed:
Debug.WriteLine("SDL2 cannot change to fixed-size windows at runtime.");
break;
}
}
} }
WindowBorderChanged(this, EventArgs.Empty); if (Exists)
{
WindowBorderChanged(this, EventArgs.Empty);
}
} }
} }
} }
@ -663,13 +701,26 @@ namespace OpenTK.Platform.SDL2
{ {
get get
{ {
int x, y; lock (sync)
SDL.SDL_GetWindowPosition(window.Handle, out x, out y); {
return new Point(x, y); if (Exists)
{
int x, y;
SDL.SDL_GetWindowPosition(window.Handle, out x, out y);
return new Point(x, y);
}
return new Point();
}
} }
set set
{ {
SDL.SDL_SetWindowPosition(window.Handle, value.X, value.Y); lock (sync)
{
if (Exists)
{
SDL.SDL_SetWindowPosition(window.Handle, value.X, value.Y);
}
}
} }
} }
@ -677,13 +728,26 @@ namespace OpenTK.Platform.SDL2
{ {
get get
{ {
int w, h; lock (sync)
SDL.SDL_GetWindowSize(window.Handle, out w, out h); {
return new Size(w, h); if (Exists)
{
int w, h;
SDL.SDL_GetWindowSize(window.Handle, out w, out h);
return new Size(w, h);
}
return new Size();
}
} }
set set
{ {
SDL.SDL_SetWindowSize(window.Handle, value.Width, value.Height); lock (sync)
{
if (Exists)
{
SDL.SDL_SetWindowSize(window.Handle, value.Width, value.Height);
}
}
} }
} }
@ -779,8 +843,14 @@ namespace OpenTK.Platform.SDL2
} }
set set
{ {
GrabCursor(!value); lock (sync)
is_cursor_visible = value; {
if (Exists)
{
GrabCursor(!value);
is_cursor_visible = value;
}
}
} }
} }
@ -790,7 +860,6 @@ namespace OpenTK.Platform.SDL2
public void Poll() public void Poll()
{ {
throw new NotImplementedException();
} }
#endregion #endregion
@ -840,9 +909,12 @@ namespace OpenTK.Platform.SDL2
if (manual) if (manual)
{ {
Debug.Print("Disposing {0}", GetType()); Debug.Print("Disposing {0}", GetType());
if (Exists) lock (sync)
{ {
DestroyWindow(); if (Exists)
{
DestroyWindow();
}
} }
} }
else else

View file

@ -64,7 +64,14 @@ namespace OpenTK.Platform.Windows
lock (LoadLock) lock (LoadLock)
{ {
if (!wgl_loaded) // On intel drivers, wgl entry points appear to change
// when creating multiple contexts. As a workaround,
// we reload Wgl entry points every time we create a
// new context - this solves the issue without any apparent
// side-effects (i.e. the old contexts can still be handled
// using the new entry points.)
// Sigh...
// if (!wgl_loaded)
{ {
// We need to create a temp context in order to load wgl extensions (e.g. for multisampling or GL3). // We need to create a temp context in order to load wgl extensions (e.g. for multisampling or GL3).
// We cannot rely on OpenTK.Platform.Wgl until we create the context and call Wgl.LoadAll(). // We cannot rely on OpenTK.Platform.Wgl until we create the context and call Wgl.LoadAll().