Mac OS updates:

Window State support (minimize and maximize) 
Preliminary full screen support.
Preliminary support for changing the screen resolution.
This commit is contained in:
kanato 2009-01-14 19:52:15 +00:00
parent 06bac23cf8
commit 083caef1c1
6 changed files with 237 additions and 47 deletions

View file

@ -216,6 +216,14 @@ namespace OpenTK.Graphics
#endregion #endregion
/// <summary>
/// Hack for Mac OS full screen support.
/// </summary>
internal IGraphicsContext Implementation
{
get { return implementation; }
}
#region --- IGraphicsContext Members --- #region --- IGraphicsContext Members ---
/// <summary> /// <summary>

View file

@ -89,7 +89,7 @@ namespace OpenTK.Platform.MacOS
AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_BLUE_SIZE, mode.AccumulatorFormat.Blue); AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_BLUE_SIZE, mode.AccumulatorFormat.Blue);
AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_ALPHA_SIZE, mode.AccumulatorFormat.Alpha); AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_ACCUM_ALPHA_SIZE, mode.AccumulatorFormat.Alpha);
} }
//AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_FULLSCREEN); AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_FULLSCREEN);
AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_NONE); AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_NONE);
Debug.Unindent(); Debug.Unindent();
@ -103,7 +103,9 @@ namespace OpenTK.Platform.MacOS
IntPtr shareContextRef = IntPtr.Zero; IntPtr shareContextRef = IntPtr.Zero;
// Choose a pixel format with the attributes we specified. // Choose a pixel format with the attributes we specified.
myAGLPixelFormat = Agl.aglChoosePixelFormat(IntPtr.Zero, 0, aglAttributes.ToArray()); myAGLPixelFormat = Agl.aglChoosePixelFormat(QuartzDisplayDeviceDriver.MainDisplay,
0, aglAttributes.ToArray());
MyAGLReportError("aglChoosePixelFormat"); MyAGLReportError("aglChoosePixelFormat");
if (shareContext != null) if (shareContext != null)
@ -212,6 +214,16 @@ namespace OpenTK.Platform.MacOS
return Agl.aglGetCurrentContext(); return Agl.aglGetCurrentContext();
} }
internal void SetFullScreen()
{
Agl.aglSetFullScreen(contextRef, 0, 0, 0, 0);
}
internal void UnsetFullScreen()
{
SetDrawable(carbonWindow);
}
#region IGraphicsContext Members #region IGraphicsContext Members
bool first = false; bool first = false;
public void SwapBuffers() public void SwapBuffers()

View file

@ -21,6 +21,12 @@ namespace OpenTK.Platform.MacOS.Carbon
{ {
internal short V; internal short V;
internal short H; internal short H;
public Point(int x, int y)
{
V = (short)x;
H = (short)y;
}
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@ -346,6 +352,24 @@ namespace OpenTK.Platform.MacOS.Carbon
internal delegate OSStatus MacOSEventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData); internal delegate OSStatus MacOSEventHandler(IntPtr inCaller, IntPtr inEvent, IntPtr userData);
internal enum WindowPartCode : short
{
inDesk = 0,
inNoWindow = 0,
inMenuBar = 1,
inSysWindow = 2,
inContent = 3,
inDrag = 4,
inGrow = 5,
inGoAway = 6,
inZoomIn = 7,
inZoomOut = 8,
inCollapseBox = 11,
inProxyIcon = 12,
inToolbarButton = 13,
inStructure = 15,
}
#endregion #endregion
#region --- Carbon API Methods --- #region --- Carbon API Methods ---
@ -778,6 +802,51 @@ namespace OpenTK.Platform.MacOS.Carbon
#endregion #endregion
[DllImport(carbon)]
internal static extern bool IsWindowCollapsed(IntPtr windowRef);
[DllImport(carbon, EntryPoint = "CollapseWindow")]
static extern OSStatus _CollapseWindow(IntPtr windowRef, bool collapse);
internal static void CollapseWindow(IntPtr windowRef, bool collapse)
{
OSStatus error = _CollapseWindow(windowRef, collapse);
if (error != OSStatus.NoError)
{
throw new MacOSException(error);
}
}
[DllImport(carbon, EntryPoint="IsWindowInStandardState")]
static extern bool _IsWindowInStandardState(IntPtr windowRef, IntPtr inIdealSize, IntPtr outIdealStandardState);
internal static bool IsWindowInStandardState(IntPtr windowRef)
{
return _IsWindowInStandardState(windowRef, IntPtr.Zero, IntPtr.Zero);
}
[DllImport(carbon, EntryPoint = "ZoomWindowIdeal")]
unsafe static extern OSStatus _ZoomWindowIdeal(IntPtr windowRef, short inPartCode, IntPtr toIdealSize);
internal static void ZoomWindowIdeal(IntPtr windowRef, WindowPartCode inPartCode, ref Point toIdealSize)
{
Point pt = toIdealSize;
OSStatus error ;
IntPtr handle = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Point)));
Marshal.StructureToPtr(toIdealSize, handle, false);
error = _ZoomWindowIdeal(windowRef, (short)inPartCode, handle);
toIdealSize = (Point)Marshal.PtrToStructure(handle,typeof(Point));
Marshal.FreeHGlobal(handle);
if (error != OSStatus.NoError)
{
throw new MacOSException(error);
}
}
} }

View file

@ -44,5 +44,8 @@ namespace OpenTK.Platform.MacOS.Carbon
[DllImport(appServices, EntryPoint = "CGDisplayAvailableModes")] [DllImport(appServices, EntryPoint = "CGDisplayAvailableModes")]
internal static extern IntPtr DisplayAvailableModes(IntPtr display); internal static extern IntPtr DisplayAvailableModes(IntPtr display);
[DllImport(appServices, EntryPoint = "CGDisplaySwitchToMode")]
internal static extern IntPtr DisplaySwitchToMode(IntPtr display, IntPtr displayMode);
} }
} }

View file

@ -18,8 +18,8 @@ namespace OpenTK.Platform.MacOS
using Carbon; using Carbon;
using Graphics; using Graphics;
class CarbonGLNative : INativeGLWindow class CarbonGLNative : INativeGLWindow
{ {
CarbonWindowInfo window; CarbonWindowInfo window;
CarbonInput mInputDriver; CarbonInput mInputDriver;
GraphicsContext context; GraphicsContext context;
@ -45,9 +45,9 @@ namespace OpenTK.Platform.MacOS
Application.Initialize(); Application.Initialize();
} }
public CarbonGLNative() public CarbonGLNative()
: this(WindowClass.Document, : this(WindowClass.Document,
WindowAttributes.StandardDocument | WindowAttributes.StandardDocument |
WindowAttributes.StandardHandler | WindowAttributes.StandardHandler |
WindowAttributes.InWindowMenu | WindowAttributes.InWindowMenu |
WindowAttributes.LiveResize) WindowAttributes.LiveResize)
{ {
@ -58,7 +58,7 @@ namespace OpenTK.Platform.MacOS
mWindowClass = @class; mWindowClass = @class;
mWindowAttrib = attrib; mWindowAttrib = attrib;
} }
~CarbonGLNative() ~CarbonGLNative()
{ {
@ -81,12 +81,12 @@ namespace OpenTK.Platform.MacOS
if (disposing) if (disposing)
{ {
mWindows.Remove(window.WindowRef); mWindows.Remove(window.WindowRef);
window.Dispose(); window.Dispose();
window = null; window = null;
} }
DisposeUPP(); DisposeUPP();
} }
@ -131,12 +131,6 @@ namespace OpenTK.Platform.MacOS
System.Diagnostics.Debug.Print("Attached window events."); System.Diagnostics.Debug.Print("Attached window events.");
} }
public void Activate()
{
API.SelectWindow(window.WindowRef);
}
void ConnectEvents() void ConnectEvents()
{ {
mInputDriver = new CarbonInput(); mInputDriver = new CarbonInput();
@ -167,6 +161,7 @@ namespace OpenTK.Platform.MacOS
API.InstallWindowEventHandler(window.WindowRef, uppHandler, eventTypes, window.WindowRef, IntPtr.Zero); API.InstallWindowEventHandler(window.WindowRef, uppHandler, eventTypes, window.WindowRef, IntPtr.Zero);
} }
public string Title public string Title
{ {
get get
@ -180,6 +175,10 @@ namespace OpenTK.Platform.MacOS
} }
} }
public void Activate()
{
API.SelectWindow(window.WindowRef);
}
public void Show() public void Show()
{ {
IntPtr parent = IntPtr.Zero; IntPtr parent = IntPtr.Zero;
@ -195,8 +194,8 @@ namespace OpenTK.Platform.MacOS
public bool Visible public bool Visible
{ {
get { return API.IsWindowVisible(window.WindowRef); } get { return API.IsWindowVisible(window.WindowRef); }
set set
{ {
if (value && Visible == false) if (value && Visible == false)
Show(); Show();
else else
@ -208,7 +207,6 @@ namespace OpenTK.Platform.MacOS
get { return mIsDisposed; } get { return mIsDisposed; }
} }
public WindowPositionMethod WindowPositionMethod public WindowPositionMethod WindowPositionMethod
{ {
get { return mPositionMethod; } get { return mPositionMethod; }
@ -232,7 +230,7 @@ namespace OpenTK.Platform.MacOS
EventInfo evt = new EventInfo(inEvent); EventInfo evt = new EventInfo(inEvent);
CarbonGLNative window = (CarbonGLNative)reference.Target; CarbonGLNative window = (CarbonGLNative)reference.Target;
//Debug.Print("Processing {0} event for {1}.", evt, window.window); //Debug.Print("Processing {0} event for {1}.", evt, window.window);
if (window == null) if (window == null)
@ -241,7 +239,7 @@ namespace OpenTK.Platform.MacOS
return OSStatus.EventNotHandled; return OSStatus.EventNotHandled;
} }
switch(evt.EventClass) switch (evt.EventClass)
{ {
case EventClass.Window: case EventClass.Window:
return window.ProcessWindowEvent(inCaller, inEvent, evt, userData); return window.ProcessWindowEvent(inCaller, inEvent, evt, userData);
@ -282,7 +280,7 @@ namespace OpenTK.Platform.MacOS
case KeyboardEventKind.RawKeyUp: case KeyboardEventKind.RawKeyUp:
GetCharCodes(inEvent, out code, out charCode); GetCharCodes(inEvent, out code, out charCode);
InputDriver.Keyboard[0][Keymap[code]] = false; InputDriver.Keyboard[0][Keymap[code]] = false;
return OSStatus.EventNotHandled; return OSStatus.EventNotHandled;
case KeyboardEventKind.RawKeyModifiersChanged: case KeyboardEventKind.RawKeyModifiersChanged:
@ -295,12 +293,11 @@ namespace OpenTK.Platform.MacOS
} }
private OSStatus ProcessWindowEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData) private OSStatus ProcessWindowEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
{ {
System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Window); System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Window);
switch(evt.WindowEventKind) switch (evt.WindowEventKind)
{ {
case WindowEventKind.WindowClose: case WindowEventKind.WindowClose:
CancelEventArgs cancel = new CancelEventArgs(); CancelEventArgs cancel = new CancelEventArgs();
@ -343,7 +340,7 @@ namespace OpenTK.Platform.MacOS
(int)pt.X, (int)pt.X,
(int)(pt.Y - mTitlebarHeight)); (int)(pt.Y - mTitlebarHeight));
switch(evt.MouseEventKind) switch (evt.MouseEventKind)
{ {
case MouseEventKind.MouseDown: case MouseEventKind.MouseDown:
button = API.GetEventMouseButton(inEvent); button = API.GetEventMouseButton(inEvent);
@ -365,7 +362,7 @@ namespace OpenTK.Platform.MacOS
break; break;
case MouseEventKind.MouseUp: case MouseEventKind.MouseUp:
switch (button) switch (button)
{ {
@ -381,14 +378,14 @@ namespace OpenTK.Platform.MacOS
InputDriver.Mouse[0][OpenTK.Input.MouseButton.Middle] = false; InputDriver.Mouse[0][OpenTK.Input.MouseButton.Middle] = false;
break; break;
} }
button = API.GetEventMouseButton(inEvent); button = API.GetEventMouseButton(inEvent);
break; break;
case MouseEventKind.MouseMoved: case MouseEventKind.MouseMoved:
case MouseEventKind.MouseDragged: case MouseEventKind.MouseDragged:
//Debug.Print("MouseMoved: {0}", InputDriver.Mouse[0].Position); //Debug.Print("MouseMoved: {0}", InputDriver.Mouse[0].Position);
return OSStatus.EventNotHandled; return OSStatus.EventNotHandled;
@ -399,10 +396,9 @@ namespace OpenTK.Platform.MacOS
return OSStatus.EventNotHandled; return OSStatus.EventNotHandled;
} }
return OSStatus.EventNotHandled; return OSStatus.EventNotHandled;
} }
private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode) private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode)
{ {
code = API.GetEventKeyboardKeyCode(inEvent); code = API.GetEventKeyboardKeyCode(inEvent);
@ -439,7 +435,6 @@ namespace OpenTK.Platform.MacOS
} }
Rect GetRegion() Rect GetRegion()
{ {
Rect retval = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion); Rect retval = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion);
@ -527,14 +522,13 @@ namespace OpenTK.Platform.MacOS
this.context.MakeCurrent(window); this.context.MakeCurrent(window);
context = this.context; context = this.context;
} }
public void DestroyWindow() public void DestroyWindow()
{ {
Dispose(); Dispose();
} }
public void ProcessEvents() public void ProcessEvents()
{ {
Application.ProcessEvents(); Application.ProcessEvents();
@ -544,7 +538,6 @@ namespace OpenTK.Platform.MacOS
{ {
throw new Exception("The method or operation is not implemented."); throw new Exception("The method or operation is not implemented.");
} }
public void PointToScreen(ref System.Drawing.Point p) public void PointToScreen(ref System.Drawing.Point p)
{ {
throw new Exception("The method or operation is not implemented."); throw new Exception("The method or operation is not implemented.");
@ -567,7 +560,7 @@ namespace OpenTK.Platform.MacOS
public OpenTK.Input.IInputDriver InputDriver public OpenTK.Input.IInputDriver InputDriver
{ {
get get
{ {
return mInputDriver; return mInputDriver;
} }
@ -586,7 +579,6 @@ namespace OpenTK.Platform.MacOS
} }
public event CreateEvent Create; public event CreateEvent Create;
public event DestroyEvent Destroy; public event DestroyEvent Destroy;
#endregion #endregion
@ -604,11 +596,65 @@ namespace OpenTK.Platform.MacOS
{ {
get get
{ {
return windowState; if (windowState == WindowState.Fullscreen)
return WindowState.Fullscreen;
if (Carbon.API.IsWindowCollapsed(window.WindowRef))
return WindowState.Minimized;
if (Carbon.API.IsWindowInStandardState(window.WindowRef))
{
return WindowState.Maximized;
}
return WindowState.Normal;
} }
set set
{ {
if (value == WindowState)
return;
Debug.Print("Switching window state from {0} to {1}", WindowState, value);
if (WindowState == WindowState.Fullscreen)
{
((AglContext)context.Implementation).UnsetFullScreen();
}
if (WindowState == WindowState.Minimized)
{
API.CollapseWindow(window.WindowRef, false);
}
Point idealSize;
switch (value)
{
case WindowState.Fullscreen:
((AglContext)context.Implementation).SetFullScreen();
context.Update(WindowInfo);
break;
case WindowState.Maximized:
idealSize = new Point(9000, 9000);
API.ZoomWindowIdeal(window.WindowRef, WindowPartCode.inZoomOut, ref idealSize);
break;
case WindowState.Normal:
if (WindowState == WindowState.Maximized)
{
idealSize = new Point();
API.ZoomWindowIdeal(window.WindowRef, WindowPartCode.inZoomIn, ref idealSize);
}
break;
case WindowState.Minimized:
API.CollapseWindow(window.WindowRef, true);
break;
}
windowState = value; windowState = value;
} }
} }
@ -621,16 +667,16 @@ namespace OpenTK.Platform.MacOS
set set
{ {
windowBorder = value; windowBorder = value;
if (windowBorder == WindowBorder.Resizable) if (windowBorder == WindowBorder.Resizable)
{ {
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.Resizable | WindowAttributes.FullZoom, API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.Resizable | WindowAttributes.FullZoom,
WindowAttributes.NoAttributes); WindowAttributes.NoAttributes);
} }
else if (windowBorder == WindowBorder.Fixed) else if (windowBorder == WindowBorder.Fixed)
{ {
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.NoAttributes, API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.NoAttributes,
WindowAttributes.Resizable | WindowAttributes.FullZoom); WindowAttributes.Resizable | WindowAttributes.FullZoom);
} }
} }
} }

View file

@ -11,7 +11,13 @@ namespace OpenTK.Platform.MacOS
class QuartzDisplayDeviceDriver : IDisplayDeviceDriver class QuartzDisplayDeviceDriver : IDisplayDeviceDriver
{ {
static object display_lock = new object(); static object display_lock = new object();
static Dictionary<DisplayDevice, IntPtr> displayMap =
new Dictionary<DisplayDevice, IntPtr>();
static IntPtr mainDisplay;
internal static IntPtr MainDisplay { get { return mainDisplay; } }
static QuartzDisplayDeviceDriver() static QuartzDisplayDeviceDriver()
{ {
//lock (display_lock) //lock (display_lock)
@ -55,6 +61,9 @@ namespace OpenTK.Platform.MacOS
// main display. // main display.
bool primary = (i == 0); bool primary = (i == 0);
if (primary)
mainDisplay = currentDisplay;
// gets current settings // gets current settings
int currentWidth = CG.DisplayPixelsWide(currentDisplay); int currentWidth = CG.DisplayPixelsWide(currentDisplay);
int currentHeight = CG.DisplayPixelsHigh(currentDisplay); int currentHeight = CG.DisplayPixelsHigh(currentDisplay);
@ -94,6 +103,8 @@ namespace OpenTK.Platform.MacOS
OpenTK.Graphics.DisplayDevice opentk_dev = OpenTK.Graphics.DisplayDevice opentk_dev =
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res); new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res);
displayMap.Add(opentk_dev, currentDisplay);
} }
Debug.Unindent(); Debug.Unindent();
@ -102,14 +113,55 @@ namespace OpenTK.Platform.MacOS
#region IDisplayDeviceDriver Members #region IDisplayDeviceDriver Members
Dictionary<IntPtr, IntPtr> storedModes = new Dictionary<IntPtr, IntPtr>();
public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution) public bool TryChangeResolution(DisplayDevice device, DisplayResolution resolution)
{ {
IntPtr display = displayMap[device];
IntPtr currentModePtr = CG.DisplayCurrentMode(display);
if (storedModes.ContainsKey(display) == false)
{
storedModes.Add(display, currentModePtr);
}
IntPtr displayModesPtr = CG.DisplayAvailableModes(display);
CFArray displayModes = new CFArray(displayModesPtr);
for (int j = 0; j < displayModes.Count; j++)
{
CFDictionary dict = new CFDictionary(displayModes[j]);
int width = (int)dict.GetNumberValue("Width");
int height = (int)dict.GetNumberValue("Height");
int bpp = (int)dict.GetNumberValue("BitsPerPixel");
double freq = dict.GetNumberValue("RefreshRate");
if (width == resolution.Width &&
height == resolution.Height &&
bpp == resolution.BitsPerPixel &&
freq == resolution.RefreshRate)
{
CG.DisplaySwitchToMode(display, displayModes[j]);
return true;
}
}
return false; return false;
} }
public bool TryRestoreResolution(DisplayDevice device) public bool TryRestoreResolution(DisplayDevice device)
{ {
IntPtr display = displayMap[device];
if (storedModes.ContainsKey(display))
{
CG.DisplaySwitchToMode(display, storedModes[display]);
return true;
}
return false; return false;
} }