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
/// <summary>
/// Hack for Mac OS full screen support.
/// </summary>
internal IGraphicsContext Implementation
{
get { return implementation; }
}
#region --- IGraphicsContext Members ---
/// <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_ALPHA_SIZE, mode.AccumulatorFormat.Alpha);
}
//AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_FULLSCREEN);
AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_FULLSCREEN);
AddPixelAttrib(aglAttributes, Agl.PixelFormatAttribute.AGL_NONE);
Debug.Unindent();
@ -103,7 +103,9 @@ namespace OpenTK.Platform.MacOS
IntPtr shareContextRef = IntPtr.Zero;
// 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");
if (shareContext != null)
@ -212,6 +214,16 @@ namespace OpenTK.Platform.MacOS
return Agl.aglGetCurrentContext();
}
internal void SetFullScreen()
{
Agl.aglSetFullScreen(contextRef, 0, 0, 0, 0);
}
internal void UnsetFullScreen()
{
SetDrawable(carbonWindow);
}
#region IGraphicsContext Members
bool first = false;
public void SwapBuffers()

View file

@ -21,6 +21,12 @@ namespace OpenTK.Platform.MacOS.Carbon
{
internal short V;
internal short H;
public Point(int x, int y)
{
V = (short)x;
H = (short)y;
}
}
[StructLayout(LayoutKind.Sequential)]
@ -346,6 +352,24 @@ namespace OpenTK.Platform.MacOS.Carbon
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
#region --- Carbon API Methods ---
@ -778,6 +802,51 @@ namespace OpenTK.Platform.MacOS.Carbon
#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")]
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 Graphics;
class CarbonGLNative : INativeGLWindow
{
class CarbonGLNative : INativeGLWindow
{
CarbonWindowInfo window;
CarbonInput mInputDriver;
GraphicsContext context;
@ -81,9 +81,9 @@ namespace OpenTK.Platform.MacOS
if (disposing)
{
mWindows.Remove(window.WindowRef);
mWindows.Remove(window.WindowRef);
window.Dispose();
window.Dispose();
window = null;
}
@ -131,12 +131,6 @@ namespace OpenTK.Platform.MacOS
System.Diagnostics.Debug.Print("Attached window events.");
}
public void Activate()
{
API.SelectWindow(window.WindowRef);
}
void ConnectEvents()
{
mInputDriver = new CarbonInput();
@ -167,6 +161,7 @@ namespace OpenTK.Platform.MacOS
API.InstallWindowEventHandler(window.WindowRef, uppHandler, eventTypes, window.WindowRef, IntPtr.Zero);
}
public string Title
{
get
@ -180,6 +175,10 @@ namespace OpenTK.Platform.MacOS
}
}
public void Activate()
{
API.SelectWindow(window.WindowRef);
}
public void Show()
{
IntPtr parent = IntPtr.Zero;
@ -208,7 +207,6 @@ namespace OpenTK.Platform.MacOS
get { return mIsDisposed; }
}
public WindowPositionMethod WindowPositionMethod
{
get { return mPositionMethod; }
@ -241,7 +239,7 @@ namespace OpenTK.Platform.MacOS
return OSStatus.EventNotHandled;
}
switch(evt.EventClass)
switch (evt.EventClass)
{
case EventClass.Window:
return window.ProcessWindowEvent(inCaller, inEvent, evt, userData);
@ -295,12 +293,11 @@ namespace OpenTK.Platform.MacOS
}
private OSStatus ProcessWindowEvent(IntPtr inCaller, IntPtr inEvent, EventInfo evt, IntPtr userData)
{
System.Diagnostics.Debug.Assert(evt.EventClass == EventClass.Window);
switch(evt.WindowEventKind)
switch (evt.WindowEventKind)
{
case WindowEventKind.WindowClose:
CancelEventArgs cancel = new CancelEventArgs();
@ -343,7 +340,7 @@ namespace OpenTK.Platform.MacOS
(int)pt.X,
(int)(pt.Y - mTitlebarHeight));
switch(evt.MouseEventKind)
switch (evt.MouseEventKind)
{
case MouseEventKind.MouseDown:
button = API.GetEventMouseButton(inEvent);
@ -399,10 +396,9 @@ namespace OpenTK.Platform.MacOS
return OSStatus.EventNotHandled;
}
return OSStatus.EventNotHandled;
return OSStatus.EventNotHandled;
}
private static void GetCharCodes(IntPtr inEvent, out MacOSKeyCode code, out char charCode)
{
code = API.GetEventKeyboardKeyCode(inEvent);
@ -439,7 +435,6 @@ namespace OpenTK.Platform.MacOS
}
Rect GetRegion()
{
Rect retval = API.GetWindowBounds(window.WindowRef, WindowRegionCode.ContentRegion);
@ -534,7 +529,6 @@ namespace OpenTK.Platform.MacOS
{
Dispose();
}
public void ProcessEvents()
{
Application.ProcessEvents();
@ -544,7 +538,6 @@ namespace OpenTK.Platform.MacOS
{
throw new Exception("The method or operation is not implemented.");
}
public void PointToScreen(ref System.Drawing.Point p)
{
throw new Exception("The method or operation is not implemented.");
@ -586,7 +579,6 @@ namespace OpenTK.Platform.MacOS
}
public event CreateEvent Create;
public event DestroyEvent Destroy;
#endregion
@ -604,11 +596,65 @@ namespace OpenTK.Platform.MacOS
{
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
{
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;
}
}
@ -624,13 +670,13 @@ namespace OpenTK.Platform.MacOS
if (windowBorder == WindowBorder.Resizable)
{
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.Resizable | WindowAttributes.FullZoom,
WindowAttributes.NoAttributes);
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.Resizable | WindowAttributes.FullZoom,
WindowAttributes.NoAttributes);
}
else if (windowBorder == WindowBorder.Fixed)
{
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.NoAttributes,
WindowAttributes.Resizable | WindowAttributes.FullZoom);
API.ChangeWindowAttributes(window.WindowRef, WindowAttributes.NoAttributes,
WindowAttributes.Resizable | WindowAttributes.FullZoom);
}
}
}

View file

@ -12,6 +12,12 @@ namespace OpenTK.Platform.MacOS
{
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()
{
//lock (display_lock)
@ -55,6 +61,9 @@ namespace OpenTK.Platform.MacOS
// main display.
bool primary = (i == 0);
if (primary)
mainDisplay = currentDisplay;
// gets current settings
int currentWidth = CG.DisplayPixelsWide(currentDisplay);
int currentHeight = CG.DisplayPixelsHigh(currentDisplay);
@ -94,6 +103,8 @@ namespace OpenTK.Platform.MacOS
OpenTK.Graphics.DisplayDevice opentk_dev =
new DisplayDevice(opentk_dev_current_res, primary, opentk_dev_available_res);
displayMap.Add(opentk_dev, currentDisplay);
}
Debug.Unindent();
@ -102,14 +113,55 @@ namespace OpenTK.Platform.MacOS
#region IDisplayDeviceDriver Members
Dictionary<IntPtr, IntPtr> storedModes = new Dictionary<IntPtr, IntPtr>();
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;
}
public bool TryRestoreResolution(DisplayDevice device)
{
IntPtr display = displayMap[device];
if (storedModes.ContainsKey(display))
{
CG.DisplaySwitchToMode(display, storedModes[display]);
return true;
}
return false;
}