Opentk/Source/OpenTK/Platform/MacOS/CocoaNativeWindow.cs

1197 lines
46 KiB
C#
Raw Normal View History

2014-04-23 18:15:09 +00:00
#region License
//
// CocoaNativeWindow.cs
//
// Author:
// Olle Håkansson <ollhak@gmail.com>
//
// Copyright (c) 2014 Olle Håkansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
2014-04-20 08:08:44 +00:00
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
2014-04-30 06:38:19 +00:00
using System.Runtime.InteropServices;
using System.Threading;
using OpenTK.Graphics;
using OpenTK.Input;
2014-04-18 20:30:50 +00:00
namespace OpenTK.Platform.MacOS
{
class CocoaNativeWindow : INativeWindow
{
static int UniqueId;
2014-04-20 08:08:44 +00:00
public event EventHandler<EventArgs> Move = delegate { };
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
static readonly IntPtr selNextEventMatchingMask = Selector.Get("nextEventMatchingMask:untilDate:inMode:dequeue:");
static readonly IntPtr selSendEvent = Selector.Get("sendEvent:");
//static readonly IntPtr selUpdateWindows = Selector.Get("updateWindows");
2014-04-20 08:08:44 +00:00
static readonly IntPtr selConvertRectFromScreen = Selector.Get("convertRectFromScreen:");
static readonly IntPtr selConvertRectToScreen = Selector.Get("convertRectToScreen:");
2014-04-20 20:26:26 +00:00
static readonly IntPtr selPerformClose = Selector.Get("performClose:");
2014-04-20 08:08:44 +00:00
static readonly IntPtr selClose = Selector.Get("close");
static readonly IntPtr selTitle = Selector.Get("title");
static readonly IntPtr selSetTitle = Selector.Get("setTitle:");
static readonly IntPtr selSetApplicationIconImage = Selector.Get("setApplicationIconImage:");
static readonly IntPtr selIsKeyWindow = Selector.Get("isKeyWindow");
static readonly IntPtr selIsVisible = Selector.Get("isVisible");
static readonly IntPtr selSetIsVisible = Selector.Get("setIsVisible:");
static readonly IntPtr selFrame = Selector.Get("frame");
static readonly IntPtr selVisibleFrame = Selector.Get("visibleFrame");
2014-04-20 08:08:44 +00:00
static readonly IntPtr selBounds = Selector.Get("bounds");
static readonly IntPtr selScreen = Selector.Get("screen");
static readonly IntPtr selSetFrame = Selector.Get("setFrame:display:");
static readonly IntPtr selConvertRectToBacking = Selector.Get("convertRectToBacking:");
static readonly IntPtr selConvertRectFromBacking = Selector.Get("convertRectFromBacking:");
static readonly IntPtr selFrameRectForContentRect = Selector.Get("frameRectForContentRect:");
static readonly IntPtr selType = Selector.Get("type");
static readonly IntPtr selKeyCode = Selector.Get("keyCode");
static readonly IntPtr selModifierFlags = Selector.Get("modifierFlags");
static readonly IntPtr selIsARepeat = Selector.Get("isARepeat");
static readonly IntPtr selCharactersIgnoringModifiers = Selector.Get("charactersIgnoringModifiers");
static readonly IntPtr selAddTrackingArea = Selector.Get("addTrackingArea:");
static readonly IntPtr selRemoveTrackingArea = Selector.Get("removeTrackingArea:");
static readonly IntPtr selTrackingArea = Selector.Get("trackingArea");
2014-04-30 06:38:19 +00:00
static readonly IntPtr selInitWithSize = Selector.Get("initWithSize:");
2014-04-20 08:08:44 +00:00
static readonly IntPtr selInitWithRect = Selector.Get("initWithRect:options:owner:userInfo:");
static readonly IntPtr selOwner = Selector.Get("owner");
static readonly IntPtr selLocationInWindowOwner = Selector.Get("locationInWindow");
static readonly IntPtr selHide = Selector.Get("hide");
static readonly IntPtr selUnhide = Selector.Get("unhide");
static readonly IntPtr selScrollingDeltaY = Selector.Get("scrollingDeltaY");
static readonly IntPtr selButtonNumber = Selector.Get("buttonNumber");
static readonly IntPtr selSetStyleMask = Selector.Get("setStyleMask:");
2014-04-20 20:26:26 +00:00
static readonly IntPtr selStyleMask = Selector.Get("styleMask");
2014-04-22 19:39:17 +00:00
static readonly IntPtr selHasPreciseScrollingDeltas = Selector.Get("hasPreciseScrollingDeltas");
//static readonly IntPtr selIsMiniaturized = Selector.Get("isMiniaturized");
//static readonly IntPtr selIsZoomed = Selector.Get("isZoomed");
2014-04-22 19:39:17 +00:00
//static readonly IntPtr selPerformMiniaturize = Selector.Get("performMiniaturize:");
2014-04-20 08:08:44 +00:00
static readonly IntPtr selMiniaturize = Selector.Get("miniaturize:");
static readonly IntPtr selDeminiaturize = Selector.Get("deminiaturize:");
//static readonly IntPtr selPerformZoom = Selector.Get("performZoom:");
2014-04-22 19:39:17 +00:00
//static readonly IntPtr selZoom = Selector.Get("zoom:");
2014-04-20 17:56:23 +00:00
static readonly IntPtr selLevel = Selector.Get("level");
static readonly IntPtr selSetLevel = Selector.Get("setLevel:");
static readonly IntPtr selPresentationOptions = Selector.Get("presentationOptions");
static readonly IntPtr selSetPresentationOptions = Selector.Get("setPresentationOptions:");
//static readonly IntPtr selIsInFullScreenMode = Selector.Get("isInFullScreenMode");
//static readonly IntPtr selExitFullScreenModeWithOptions = Selector.Get("exitFullScreenModeWithOptions:");
//static readonly IntPtr selEnterFullScreenModeWithOptions = Selector.Get("enterFullScreenMode:withOptions:");
2014-04-27 17:45:20 +00:00
static readonly IntPtr selArrowCursor = Selector.Get("arrowCursor");
2014-04-30 06:38:19 +00:00
static readonly IntPtr selAddCursorRect = Selector.Get("addCursorRect:cursor:");
static readonly IntPtr selInvalidateCursorRectsForView = Selector.Get("invalidateCursorRectsForView:");
static readonly IntPtr selInitWithBitmapDataPlanes =
2014-04-30 07:06:18 +00:00
Selector.Get("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:");
2014-04-30 06:38:19 +00:00
static readonly IntPtr selBitmapData = Selector.Get("bitmapData");
static readonly IntPtr selAddRepresentation = Selector.Get("addRepresentation:");
static readonly IntPtr selInitWithImageHotSpot = Selector.Get("initWithImage:hotSpot:");
2014-04-20 17:56:23 +00:00
2014-04-18 20:30:50 +00:00
static readonly IntPtr NSDefaultRunLoopMode;
2014-04-20 08:08:44 +00:00
static readonly IntPtr NSCursor;
2014-04-30 06:38:19 +00:00
static readonly IntPtr NSImage;
static readonly IntPtr NSBitmapImageRep;
static readonly IntPtr NSDeviceRGBColorSpace = Cocoa.ToNSString("NSDeviceRGBColorSpace");
2014-04-18 20:30:50 +00:00
static CocoaNativeWindow()
{
Cocoa.Initialize();
NSApplication.Initialize(); // Problem: This does not allow creating a separate app and using CocoaNativeWindow.
2014-04-18 20:30:50 +00:00
NSDefaultRunLoopMode = Cocoa.GetStringConstant(Cocoa.FoundationLibrary, "NSDefaultRunLoopMode");
2014-04-20 08:08:44 +00:00
NSCursor = Class.Get("NSCursor");
2014-04-30 06:38:19 +00:00
NSImage = Class.Get("NSImage");
NSBitmapImageRep = Class.Get("NSBitmapImageRep");
2014-04-18 20:30:50 +00:00
}
2014-04-19 10:17:14 +00:00
private CocoaWindowInfo windowInfo;
private IntPtr windowClass;
2014-04-20 08:08:44 +00:00
private IntPtr trackingArea;
private bool disposed = false;
private bool exists;
2014-04-20 08:08:44 +00:00
private bool cursorVisible = true;
private System.Drawing.Icon icon;
private LegacyInputDriver inputDriver = new LegacyInputDriver();
private WindowBorder windowBorder = WindowBorder.Resizable;
private Nullable<WindowBorder> deferredWindowBorder;
private Nullable<WindowBorder> previousWindowBorder;
private WindowState windowState = WindowState.Normal;
2014-04-20 08:08:44 +00:00
private OpenTK.Input.KeyboardKeyEventArgs keyArgs = new OpenTK.Input.KeyboardKeyEventArgs();
private KeyPressEventArgs keyPressArgs = new KeyPressEventArgs((char)0);
2014-04-21 18:32:16 +00:00
private string title;
private RectangleF previousBounds;
2014-04-21 18:32:16 +00:00
private int normalLevel;
private bool shouldClose;
private int suppressResize;
2014-04-27 17:45:20 +00:00
private bool cursorInsideWindow = true;
private MouseCursor selectedCursor = MouseCursor.Default; // user-selected cursor
2014-04-19 10:17:14 +00:00
2014-04-27 17:45:20 +00:00
private const float scrollFactor = 120.0f;
2014-04-21 18:32:16 +00:00
private const bool exclusiveFullscreen = false;
2014-04-20 17:56:23 +00:00
2014-04-18 20:30:50 +00:00
public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
2014-04-19 10:17:14 +00:00
// Create the window class
Interlocked.Increment(ref UniqueId);
windowClass = Class.AllocateClass("OpenTK_GameWindow" + UniqueId, "NSWindow");
Class.RegisterMethod(windowClass, new WindowKeyDownDelegate(WindowKeyDown), "keyDown:", "v@:@");
2014-04-19 10:17:14 +00:00
Class.RegisterMethod(windowClass, new WindowDidResizeDelegate(WindowDidResize), "windowDidResize:", "v@:@");
2014-04-20 17:56:23 +00:00
Class.RegisterMethod(windowClass, new WindowDidMoveDelegate(WindowDidMove), "windowDidMove:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidBecomeKeyDelegate(WindowDidBecomeKey), "windowDidBecomeKey:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidResignKeyDelegate(WindowDidResignKey), "windowDidResignKey:", "v@:@");
Class.RegisterMethod(windowClass, new WindowWillMiniaturizeDelegate(WindowWillMiniaturize), "windowWillMiniaturize:", "v@:@");
2014-04-20 20:26:26 +00:00
Class.RegisterMethod(windowClass, new WindowDidMiniaturizeDelegate(WindowDidMiniaturize), "windowDidMiniaturize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowDidDeminiaturizeDelegate(WindowDidDeminiaturize), "windowDidDeminiaturize:", "v@:@");
Class.RegisterMethod(windowClass, new WindowShouldZoomToFrameDelegate(WindowShouldZoomToFrame), "windowShouldZoom:toFrame:", "b@:@{NSRect={NSPoint=ff}{NSSize=ff}}");
2014-04-20 08:08:44 +00:00
Class.RegisterMethod(windowClass, new WindowShouldCloseDelegate(WindowShouldClose), "windowShouldClose:", "b@:@");
Class.RegisterMethod(windowClass, new AcceptsFirstResponderDelegate(AcceptsFirstResponder), "acceptsFirstResponder", "b@:");
Class.RegisterMethod(windowClass, new CanBecomeKeyWindowDelegate(CanBecomeKeyWindow), "canBecomeKeyWindow", "b@:");
Class.RegisterMethod(windowClass, new CanBecomeMainWindowDelegate(CanBecomeMainWindow), "canBecomeMainWindow", "b@:");
2014-04-19 10:17:14 +00:00
Class.RegisterClass(windowClass);
2014-04-30 06:38:19 +00:00
IntPtr viewClass = Class.AllocateClass("OpenTK_NSView" + UniqueId, "NSView");
Class.RegisterMethod(viewClass, new ResetCursorRectsDelegate(ResetCursorRects), "resetCursorRects", "v@:");
Class.RegisterClass(viewClass);
2014-04-19 10:17:14 +00:00
// Create window instance
2014-04-18 20:30:50 +00:00
var contentRect = new System.Drawing.RectangleF(x, y, width, height);
2014-04-20 08:08:44 +00:00
var style = GetStyleMask(windowBorder);
2014-04-18 20:30:50 +00:00
var bufferingType = NSBackingStore.Buffered;
IntPtr windowPtr;
2014-04-19 10:17:14 +00:00
windowPtr = Cocoa.SendIntPtr(windowClass, Selector.Alloc);
2014-04-18 20:30:50 +00:00
windowPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("initWithContentRect:styleMask:backing:defer:"), contentRect, (int)style, (int)bufferingType, false);
2014-04-30 06:38:19 +00:00
// Replace view with our custom implementation
// that overrides resetCursorRects (maybe there is
// a better way to implement this override?)
// Existing view:
IntPtr viewPtr = Cocoa.SendIntPtr(windowPtr, Selector.Get("contentView"));
// Our custom view with the same bounds:
viewPtr = Cocoa.SendIntPtr(
Cocoa.SendIntPtr(viewClass, Selector.Alloc),
Selector.Get("initWithFrame:"),
Cocoa.SendRect(viewPtr, selBounds));
if (viewPtr != IntPtr.Zero)
{
Cocoa.SendVoid(windowPtr, Selector.Get("setContentView:"), viewPtr);
}
2014-04-20 17:56:23 +00:00
windowInfo = new CocoaWindowInfo(windowPtr);
2014-04-18 20:30:50 +00:00
2014-04-19 10:17:14 +00:00
// Set up behavior
Cocoa.SendIntPtr(windowPtr, Selector.Get("setDelegate:"), windowPtr); // The window class acts as its own delegate
Cocoa.SendVoid(windowPtr, Selector.Get("cascadeTopLeftFromPoint:"), System.Drawing.PointF.Empty);
Cocoa.SendVoid(windowPtr, Selector.Get("makeKeyWindow"));
2014-04-20 17:56:23 +00:00
SetTitle(title, false);
2014-04-18 20:30:50 +00:00
2014-04-20 08:08:44 +00:00
ResetTrackingArea();
exists = true;
NSApplication.Quit += ApplicationQuit;
2014-04-18 20:30:50 +00:00
}
delegate void WindowKeyDownDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
2014-04-19 10:17:14 +00:00
delegate void WindowDidResizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
2014-04-20 17:56:23 +00:00
delegate void WindowDidMoveDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
delegate void WindowDidBecomeKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
delegate void WindowDidResignKeyDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
delegate void WindowWillMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
2014-04-20 20:26:26 +00:00
delegate void WindowDidMiniaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
delegate void WindowDidDeminiaturizeDelegate(IntPtr self, IntPtr cmd, IntPtr notification);
delegate bool WindowShouldZoomToFrameDelegate(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame);
2014-04-20 08:08:44 +00:00
delegate bool WindowShouldCloseDelegate(IntPtr self, IntPtr cmd, IntPtr sender);
delegate bool AcceptsFirstResponderDelegate(IntPtr self, IntPtr cmd);
delegate bool CanBecomeKeyWindowDelegate(IntPtr self, IntPtr cmd);
delegate bool CanBecomeMainWindowDelegate(IntPtr self, IntPtr cmd);
2014-04-30 06:38:19 +00:00
delegate void ResetCursorRectsDelegate(IntPtr self, IntPtr cmd);
2014-04-19 10:17:14 +00:00
private void WindowKeyDown(IntPtr self, IntPtr cmd, IntPtr notification)
{
// Steal the event to remove the "beep" sound that is normally played for unhandled key events.
}
2014-04-20 08:08:44 +00:00
private void WindowDidResize(IntPtr self, IntPtr cmd, IntPtr notification)
2014-04-19 10:17:14 +00:00
{
OnResize(true);
}
private void OnResize(bool resetTracking)
{
if (resetTracking)
{
ResetTrackingArea();
}
2014-04-19 10:17:14 +00:00
GraphicsContext.CurrentContext.Update(windowInfo);
if (suppressResize == 0)
Resize(this, EventArgs.Empty);
2014-04-20 17:56:23 +00:00
}
private void ApplicationQuit(object sender, CancelEventArgs e)
{
bool close = WindowShouldClose(windowInfo.Handle, IntPtr.Zero, IntPtr.Zero);
e.Cancel |= !close;
}
2014-04-20 17:56:23 +00:00
private void WindowDidMove(IntPtr self, IntPtr cmd, IntPtr notification)
{
2014-04-20 20:26:26 +00:00
// Problem: Called only when you stop moving for a brief moment,
// not each frame as it is on PC.
2014-04-20 17:56:23 +00:00
Move(this, EventArgs.Empty);
}
private void WindowDidBecomeKey(IntPtr self, IntPtr cmd, IntPtr notification)
{
FocusedChanged(this, EventArgs.Empty);
}
private void WindowDidResignKey(IntPtr self, IntPtr cmd, IntPtr notification)
{
FocusedChanged(this, EventArgs.Empty);
2014-04-19 10:17:14 +00:00
}
private void WindowWillMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{
// Can get stuck in weird states if we maximize, then minimize;
// restoring to the old state would override the normalBounds.
// To avoid this without adding complexity, just restore state here.
RestoreWindowState(); // Avoid getting in weird states
}
2014-04-20 20:26:26 +00:00
private void WindowDidMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{
windowState = WindowState.Minimized;
2014-04-20 20:26:26 +00:00
WindowStateChanged(this, EventArgs.Empty);
OnResize(false); // Don't set tracking area when we minimize
2014-04-20 20:26:26 +00:00
}
private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{
windowState = WindowState.Normal;
2014-04-20 20:26:26 +00:00
WindowStateChanged(this, EventArgs.Empty);
OnResize(true);
2014-04-20 20:26:26 +00:00
}
private bool WindowShouldZoomToFrame(IntPtr self, IntPtr cmd, IntPtr nsWindow, RectangleF toFrame)
{
if (windowState == WindowState.Maximized)
{
WindowState = WindowState.Normal;
}
else
{
previousBounds = InternalBounds;
previousWindowBorder = WindowBorder;
InternalBounds = toFrame;
windowState = WindowState.Maximized;
WindowStateChanged(this, EventArgs.Empty);
}
return false;
2014-04-20 20:26:26 +00:00
}
2014-04-20 08:08:44 +00:00
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
2014-04-18 20:30:50 +00:00
{
2014-04-20 08:08:44 +00:00
var cancelArgs = new CancelEventArgs();
Closing(this, cancelArgs);
if (!cancelArgs.Cancel)
{
Closed(this, EventArgs.Empty);
return true;
}
return false;
}
private bool AcceptsFirstResponder(IntPtr self, IntPtr cmd)
{
return true;
}
private bool CanBecomeKeyWindow(IntPtr self, IntPtr cmd)
{
return true;
}
private bool CanBecomeMainWindow(IntPtr self, IntPtr cmd)
{
return true;
}
private void ResetTrackingArea()
{
var owner = windowInfo.ViewHandle;
if (trackingArea != IntPtr.Zero)
{
Cocoa.SendVoid(owner, selRemoveTrackingArea, trackingArea);
2014-04-21 17:41:45 +00:00
Cocoa.SendVoid(trackingArea, Selector.Release);
2014-04-20 08:08:44 +00:00
}
var ownerBounds = Cocoa.SendRect(owner, selBounds);
2014-04-30 06:38:19 +00:00
var options = (int)(
NSTrackingAreaOptions.MouseEnteredAndExited |
NSTrackingAreaOptions.ActiveInKeyWindow |
NSTrackingAreaOptions.MouseMoved |
NSTrackingAreaOptions.CursorUpdate);
2014-04-20 08:08:44 +00:00
trackingArea = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSTrackingArea"), Selector.Alloc),
selInitWithRect, ownerBounds, options, owner, IntPtr.Zero);
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
2014-04-18 20:30:50 +00:00
}
public void Close()
{
2014-04-21 18:32:16 +00:00
shouldClose = true;
2014-04-20 08:08:44 +00:00
}
private KeyModifiers GetModifiers(NSEventModifierMask mask)
{
OpenTK.Input.KeyModifiers modifiers = 0;
if ((mask & NSEventModifierMask.ControlKeyMask) != 0) modifiers |= OpenTK.Input.KeyModifiers.Control;
if ((mask & NSEventModifierMask.ShiftKeyMask) != 0) modifiers |= OpenTK.Input.KeyModifiers.Shift;
if ((mask & NSEventModifierMask.AlternateKeyMask) != 0) modifiers |= OpenTK.Input.KeyModifiers.Alt;
return modifiers;
}
private void GetKey(ushort keyCode, NSEventModifierMask modifierFlags, OpenTK.Input.KeyboardKeyEventArgs args)
{
2014-04-25 11:38:53 +00:00
args.Key = MacOSKeyMap.GetKey((Carbon.MacOSKeyCode)keyCode);
2014-04-20 08:08:44 +00:00
args.Modifiers = GetModifiers(modifierFlags);
args.ScanCode = (uint)keyCode;
}
private MouseButton GetMouseButton(int cocoaButtonIndex)
{
if (cocoaButtonIndex == 0) return MouseButton.Left;
if (cocoaButtonIndex == 1) return MouseButton.Right;
if (cocoaButtonIndex == 2) return MouseButton.Middle;
if (cocoaButtonIndex >= (int)MouseButton.LastButton)
return MouseButton.LastButton;
return (MouseButton)cocoaButtonIndex;
2014-04-18 20:30:50 +00:00
}
public void ProcessEvents()
{
2014-04-21 17:41:45 +00:00
while (true)
{
var e = Cocoa.SendIntPtr(NSApplication.Handle, selNextEventMatchingMask, uint.MaxValue, IntPtr.Zero, NSDefaultRunLoopMode, true);
2014-04-18 20:30:50 +00:00
2014-04-21 17:41:45 +00:00
if (e == IntPtr.Zero)
break;
2014-04-18 20:30:50 +00:00
2014-04-21 17:41:45 +00:00
var type = (NSEventType)Cocoa.SendInt(e, selType);
switch (type)
{
case NSEventType.KeyDown:
2014-04-20 08:08:44 +00:00
{
2014-04-21 17:41:45 +00:00
var keyCode = Cocoa.SendUshort(e, selKeyCode);
var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags);
var isARepeat = Cocoa.SendBool(e, selIsARepeat);
GetKey(keyCode, modifierFlags, keyArgs);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, true);
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
if (!isARepeat || InputDriver.Keyboard[0].KeyRepeat)
2014-04-20 08:08:44 +00:00
{
2014-04-21 17:41:45 +00:00
KeyDown(this, keyArgs);
}
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
foreach (var c in s)
{
int intVal = (int)c;
if (!Char.IsControl(c) && (intVal < 63232 || intVal > 63235))
{
// For some reason, arrow keys (mapped 63232-63235) are seen as non-control characters, so get rid of those.
keyPressArgs.KeyChar = c;
KeyPress(this, keyPressArgs);
}
2014-04-20 08:08:44 +00:00
}
2014-04-21 17:41:45 +00:00
}
break;
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
case NSEventType.KeyUp:
{
var keyCode = Cocoa.SendUshort(e, selKeyCode);
var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags);
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
GetKey(keyCode, modifierFlags, keyArgs);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, false);
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
KeyUp(this, keyArgs);
}
break;
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
case NSEventType.MouseEntered:
2014-04-20 08:08:44 +00:00
{
2014-04-21 17:41:45 +00:00
var eventTrackingArea = Cocoa.SendIntPtr(e, selTrackingArea);
var trackingAreaOwner = Cocoa.SendIntPtr(eventTrackingArea, selOwner);
if (trackingAreaOwner == windowInfo.ViewHandle)
2014-04-20 08:08:44 +00:00
{
2014-04-27 17:45:20 +00:00
if (selectedCursor != MouseCursor.Default)
2014-04-21 17:41:45 +00:00
{
2014-04-30 06:38:19 +00:00
//SetCursor(selectedCursor);
2014-04-21 17:41:45 +00:00
}
2014-04-20 08:08:44 +00:00
2014-04-27 17:45:20 +00:00
cursorInsideWindow = true;
2014-04-21 17:41:45 +00:00
MouseEnter(this, EventArgs.Empty);
}
2014-04-20 08:08:44 +00:00
}
2014-04-21 17:41:45 +00:00
break;
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
case NSEventType.MouseExited:
2014-04-20 08:08:44 +00:00
{
2014-04-21 17:41:45 +00:00
var eventTrackingArea = Cocoa.SendIntPtr(e, selTrackingArea);
var trackingAreaOwner = Cocoa.SendIntPtr(eventTrackingArea, selOwner);
if (trackingAreaOwner == windowInfo.ViewHandle)
2014-04-20 08:08:44 +00:00
{
2014-04-27 17:45:20 +00:00
if (selectedCursor != MouseCursor.Default)
2014-04-21 17:41:45 +00:00
{
2014-04-27 17:45:20 +00:00
SetCursor(MouseCursor.Default);
2014-04-21 17:41:45 +00:00
}
2014-04-20 08:08:44 +00:00
2014-04-27 17:45:20 +00:00
cursorInsideWindow = false;
2014-04-21 17:41:45 +00:00
MouseLeave(this, EventArgs.Empty);
}
2014-04-20 08:08:44 +00:00
}
2014-04-21 17:41:45 +00:00
break;
2014-04-20 08:08:44 +00:00
2014-04-21 18:37:36 +00:00
case NSEventType.LeftMouseDragged:
case NSEventType.RightMouseDragged:
case NSEventType.OtherMouseDragged:
2014-04-21 17:41:45 +00:00
case NSEventType.MouseMoved:
{
var pf = Cocoa.SendPoint(e, selLocationInWindowOwner);
// Convert from points to pixel coordinates
var rf = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking,
new RectangleF(pf.X, pf.Y, 0, 0));
// See CocoaDrawingGuide under "Converting from Window to View Coordinates"
var p = new Point(
MathHelper.Clamp((int)Math.Round(rf.X), 0, Width),
MathHelper.Clamp((int)Math.Round(Height - rf.Y), 0, Height));
2014-04-21 17:41:45 +00:00
InputDriver.Mouse[0].Position = p;
}
break;
2014-04-20 08:08:44 +00:00
2014-04-30 06:38:19 +00:00
case NSEventType.CursorUpdate:
break;
2014-04-21 17:41:45 +00:00
case NSEventType.ScrollWheel:
{
var scrollingDelta = Cocoa.SendFloat(e, selScrollingDeltaY);
2014-04-22 19:39:17 +00:00
var factor = 1.0f;
if (Cocoa.SendBool(e, selHasPreciseScrollingDeltas))
{
2014-04-23 19:20:18 +00:00
factor = 1.0f / scrollFactor; // Problem: Don't know what factor to use here, but this seems to work.
2014-04-22 19:39:17 +00:00
}
InputDriver.Mouse[0].WheelPrecise += scrollingDelta * factor;
2014-04-21 17:41:45 +00:00
}
break;
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
case NSEventType.LeftMouseDown:
case NSEventType.RightMouseDown:
case NSEventType.OtherMouseDown:
{
var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = true;
}
break;
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
case NSEventType.LeftMouseUp:
case NSEventType.RightMouseUp:
case NSEventType.OtherMouseUp:
{
var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = false;
}
break;
}
2014-04-20 08:08:44 +00:00
2014-04-21 17:41:45 +00:00
Cocoa.SendVoid(NSApplication.Handle, selSendEvent, e);
2014-04-21 18:32:16 +00:00
}
// Handle closing
if (shouldClose)
{
shouldClose = false;
// PerformClose is equivalent to pressing the close-button, which
// does not work in a borderless window. Handle this special case.
if (GetStyleMask() == NSWindowStyle.Borderless)
{
if (WindowShouldClose(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
{
Cocoa.SendVoid(windowInfo.Handle, selClose);
}
}
else
{
Cocoa.SendVoid(windowInfo.Handle, selPerformClose, windowInfo.Handle);
}
2014-04-20 08:08:44 +00:00
}
2014-04-18 20:30:50 +00:00
}
public System.Drawing.Point PointToClient(System.Drawing.Point point)
{
2014-04-20 08:08:44 +00:00
var r = Cocoa.SendRect(windowInfo.Handle, selConvertRectFromScreen, new RectangleF(point.X, point.Y, 0, 0));
return new Point((int)r.X, (int)(GetContentViewFrame().Height - GetCurrentScreenFrame().Height - r.Y));
2014-04-18 20:30:50 +00:00
}
public System.Drawing.Point PointToScreen(System.Drawing.Point point)
{
2014-04-20 08:08:44 +00:00
var r = Cocoa.SendRect(windowInfo.Handle, selConvertRectToScreen, new RectangleF(point.X, point.Y, 0, 0));
return new Point((int)r.X, (int)(-GetContentViewFrame().Height + GetCurrentScreenFrame().Height - r.Y));
2014-04-18 20:30:50 +00:00
}
public System.Drawing.Icon Icon
{
2014-04-20 08:08:44 +00:00
get { return icon; }
2014-04-18 20:30:50 +00:00
set
{
2014-04-20 08:08:44 +00:00
icon = value;
using (Image img = icon.ToBitmap())
{
IntPtr nsimg = Cocoa.ToNSImage(img);
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg);
}
2014-04-20 08:08:44 +00:00
IconChanged(this, EventArgs.Empty);
2014-04-18 20:30:50 +00:00
}
}
public string Title
{
get
{
2014-04-20 08:08:44 +00:00
return Cocoa.FromNSString(Cocoa.SendIntPtr(windowInfo.Handle, selTitle));
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 17:56:23 +00:00
SetTitle(value, true);
2014-04-18 20:30:50 +00:00
}
}
public bool Focused
{
get
{
2014-04-20 08:08:44 +00:00
return Cocoa.SendBool(windowInfo.Handle, selIsKeyWindow);
2014-04-18 20:30:50 +00:00
}
}
public bool Visible
{
get
{
2014-04-20 08:08:44 +00:00
return Cocoa.SendBool(windowInfo.Handle, selIsVisible);
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
Cocoa.SendVoid(windowInfo.Handle, selSetIsVisible, value);
VisibleChanged(this, EventArgs.Empty);
2014-04-18 20:30:50 +00:00
}
}
public bool Exists
{
get
{
2014-04-20 08:08:44 +00:00
return exists;
2014-04-18 20:30:50 +00:00
}
}
public IWindowInfo WindowInfo
{
get
{
return windowInfo;
}
}
2014-04-20 08:08:44 +00:00
private void RestoreWindowState()
{
suppressResize++;
if (windowState == WindowState.Fullscreen)
2014-04-20 08:08:44 +00:00
{
2014-04-20 17:56:23 +00:00
SetMenuVisible(true);
if (exclusiveFullscreen)
{
OpenTK.Platform.MacOS.Carbon.CG.DisplayReleaseAll();
Cocoa.SendVoid(windowInfo.Handle, selSetLevel, normalLevel);
2014-04-20 17:56:23 +00:00
}
RestoreBorder();
InternalBounds = previousBounds;
2014-04-20 08:08:44 +00:00
}
else if (windowState == WindowState.Maximized)
2014-04-20 08:08:44 +00:00
{
RestoreBorder();
InternalBounds = previousBounds;
2014-04-20 08:08:44 +00:00
}
else if (windowState == WindowState.Minimized)
2014-04-20 08:08:44 +00:00
{
Cocoa.SendVoid(windowInfo.Handle, selDeminiaturize, windowInfo.Handle);
}
windowState = WindowState.Normal;
suppressResize--;
}
private void HideBorder()
{
suppressResize++;
SetWindowBorder(WindowBorder.Hidden);
ProcessEvents();
suppressResize--;
}
private void RestoreBorder()
{
suppressResize++;
SetWindowBorder(
deferredWindowBorder.HasValue ? deferredWindowBorder.Value :
previousWindowBorder.HasValue ? previousWindowBorder.Value :
windowBorder);
ProcessEvents();
suppressResize--;
deferredWindowBorder = null;
previousWindowBorder = null;
2014-04-20 08:08:44 +00:00
}
2014-04-18 20:30:50 +00:00
public WindowState WindowState
{
get
{
return windowState;
2014-04-18 20:30:50 +00:00
}
set
{
var oldState = windowState;
2014-04-20 08:08:44 +00:00
if (oldState == value)
return;
RestoreWindowState();
if (value == WindowState.Fullscreen)
{
2014-04-20 17:56:23 +00:00
if (exclusiveFullscreen)
{
normalLevel = Cocoa.SendInt(windowInfo.Handle, selLevel);
2014-04-20 17:56:23 +00:00
var windowLevel = OpenTK.Platform.MacOS.Carbon.CG.ShieldingWindowLevel();
OpenTK.Platform.MacOS.Carbon.CG.CaptureAllDisplays();
Cocoa.SendVoid(windowInfo.Handle, selSetLevel, windowLevel);
}
2014-04-20 08:08:44 +00:00
previousBounds = InternalBounds;
previousWindowBorder = WindowBorder;
2014-04-20 17:56:23 +00:00
SetMenuVisible(false);
HideBorder();
InternalBounds = GetCurrentScreenFrame();
windowState = value;
WindowStateChanged(this, EventArgs.Empty);
2014-04-20 17:56:23 +00:00
}
else if (value == WindowState.Maximized)
2014-04-20 08:08:44 +00:00
{
WindowShouldZoomToFrame(IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, GetCurrentScreenVisibleFrame());
2014-04-20 08:08:44 +00:00
}
2014-04-20 17:56:23 +00:00
else if (value == WindowState.Minimized)
2014-04-20 08:08:44 +00:00
{
Cocoa.SendVoid(windowInfo.Handle, selMiniaturize, windowInfo.Handle);
2014-04-20 20:26:26 +00:00
}
else if (value == WindowState.Normal)
2014-04-20 20:26:26 +00:00
{
windowState = value;
2014-04-20 20:26:26 +00:00
WindowStateChanged(this, EventArgs.Empty);
Resize(this, EventArgs.Empty);
2014-04-20 08:08:44 +00:00
}
2014-04-18 20:30:50 +00:00
}
}
public WindowBorder WindowBorder
{
2014-04-20 08:08:44 +00:00
get
{
return windowBorder;
2014-04-18 20:30:50 +00:00
}
set
{
// Do not allow border changes during fullscreen mode.
if (windowState == WindowState.Fullscreen || windowState == WindowState.Maximized)
{
deferredWindowBorder = value;
return;
}
if (windowBorder == value)
return;
SetWindowBorder(value);
2014-04-20 08:08:44 +00:00
WindowBorderChanged(this, EventArgs.Empty);
2014-04-18 20:30:50 +00:00
}
}
private void SetWindowBorder(WindowBorder windowBorder)
{
this.windowBorder = windowBorder;
UpdateWindowBorder();
}
2014-04-20 08:08:44 +00:00
private static NSWindowStyle GetStyleMask(WindowBorder windowBorder)
{
switch (windowBorder)
{
case WindowBorder.Resizable: return NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Titled | NSWindowStyle.Resizable;
case WindowBorder.Fixed: return NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Titled;
case WindowBorder.Hidden: return NSWindowStyle.Borderless;
}
return (NSWindowStyle)0;
}
2014-04-18 20:30:50 +00:00
public System.Drawing.Rectangle Bounds
{
get
{
2014-04-20 08:08:44 +00:00
var r = Cocoa.SendRect(windowInfo.Handle, selFrame);
2014-04-20 20:26:26 +00:00
return new Rectangle((int)r.X, (int)(GetCurrentScreenFrame().Height - r.Y), (int)r.Width, (int)r.Height);
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 20:26:26 +00:00
Cocoa.SendVoid(windowInfo.Handle, selSetFrame, new RectangleF(value.X, GetCurrentScreenFrame().Height - value.Y, value.Width, value.Height), true);
}
}
private System.Drawing.RectangleF InternalBounds
{
get
{
return Cocoa.SendRect(windowInfo.Handle, selFrame);
}
set
{
Cocoa.SendVoid(windowInfo.Handle, selSetFrame, value, true);
2014-04-18 20:30:50 +00:00
}
}
public System.Drawing.Point Location
{
2014-04-20 08:08:44 +00:00
get
{
return Bounds.Location;
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
var b = Bounds;
b.Location = value;
Bounds = b;
2014-04-18 20:30:50 +00:00
}
}
public System.Drawing.Size Size
{
2014-04-20 08:08:44 +00:00
get
{
return Bounds.Size;
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
var b = Bounds;
b.Y -= Bounds.Height;
b.Y += value.Height;
b.Size = value;
Bounds = b;
2014-04-18 20:30:50 +00:00
}
}
public int X
{
2014-04-20 08:08:44 +00:00
get
2014-04-18 20:30:50 +00:00
{
2014-04-20 08:08:44 +00:00
return Bounds.X;
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
var b = Bounds;
b.X = value;
Bounds = b;
2014-04-18 20:30:50 +00:00
}
}
public int Y
{
get
{
2014-04-20 08:08:44 +00:00
return Bounds.Y;
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
var b = Bounds;
b.Y = value;
Bounds = b;
2014-04-18 20:30:50 +00:00
}
}
public int Width
{
2014-04-20 08:08:44 +00:00
get { return ClientRectangle.Width; }
2014-04-18 20:30:50 +00:00
set
{
2014-04-20 20:26:26 +00:00
var s = ClientSize;
2014-04-20 08:08:44 +00:00
s.Width = value;
ClientSize = s;
2014-04-18 20:30:50 +00:00
}
}
public int Height
{
2014-04-20 08:08:44 +00:00
get { return ClientRectangle.Height; }
2014-04-18 20:30:50 +00:00
set
{
2014-04-20 20:26:26 +00:00
var s = ClientSize;
2014-04-20 08:08:44 +00:00
s.Height = value;
ClientSize = s;
2014-04-18 20:30:50 +00:00
}
}
public System.Drawing.Rectangle ClientRectangle
{
get
{
2014-04-20 08:08:44 +00:00
var contentViewBounds = Cocoa.SendRect(windowInfo.ViewHandle, selBounds);
var bounds = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking, contentViewBounds);
return new Rectangle((int)bounds.X, (int)bounds.Y, (int)bounds.Width, (int)bounds.Height);
2014-04-18 20:30:50 +00:00
}
2014-04-20 08:08:44 +00:00
set
2014-04-18 20:30:50 +00:00
{
2014-04-20 08:08:44 +00:00
ClientSize = value.Size; // Just set size, to be consistent with WinGLNative.
2014-04-18 20:30:50 +00:00
}
}
public System.Drawing.Size ClientSize
{
2014-04-20 08:08:44 +00:00
get
2014-04-18 20:30:50 +00:00
{
2014-04-20 08:08:44 +00:00
return ClientRectangle.Size;
2014-04-18 20:30:50 +00:00
}
set
{
2014-04-20 08:08:44 +00:00
var r_scaled = Cocoa.SendRect(windowInfo.Handle, selConvertRectFromBacking, new RectangleF(PointF.Empty, value));
var r = Cocoa.SendRect(windowInfo.Handle, selFrameRectForContentRect, r_scaled);
Size = new Size((int)r.Width, (int)r.Height);
2014-04-18 20:30:50 +00:00
}
}
public OpenTK.Input.IInputDriver InputDriver
{
get
{
2014-04-20 08:08:44 +00:00
return inputDriver;
2014-04-18 20:30:50 +00:00
}
}
2014-04-27 08:56:08 +00:00
public MouseCursor Cursor
{
get
{
2014-04-27 17:45:20 +00:00
return selectedCursor;
2014-04-27 08:56:08 +00:00
}
set
{
2014-04-30 06:38:19 +00:00
selectedCursor = value;
InvalidateCursorRects();
}
}
static IntPtr ToNSCursor(MouseCursor cursor)
{
// We need to allocate a NSBitmapImageRep, fill it with pixels
// and then convert it to a NSImage.
// According to the documentation, alpha-enabled formats should
// premultiply alpha, even though that "generally has negligible
// effect on output quality."
IntPtr imgdata =
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(NSBitmapImageRep, Selector.Alloc),
selInitWithBitmapDataPlanes,
IntPtr.Zero,
cursor.Width,
cursor.Height,
8,
4,
1,
0,
NSDeviceRGBColorSpace,
2014-04-30 07:06:18 +00:00
NSBitmapFormat.AlphaFirst,
2014-04-30 06:38:19 +00:00
4 * cursor.Width,
32),
Selector.Autorelease);
if (imgdata == IntPtr.Zero)
{
Debug.Print("Failed to create NSBitmapImageRep with size ({0},{1]})",
cursor.Width, cursor.Height);
return IntPtr.Zero;
}
2014-04-30 07:06:18 +00:00
// Copy the cursor data
2014-04-30 06:38:19 +00:00
int i = 0;
IntPtr data = Cocoa.SendIntPtr(imgdata, selBitmapData);
for (int y = 0; y < cursor.Height; y++)
{
for (int x = 0; x < cursor.Width; x++)
2014-04-27 17:45:20 +00:00
{
uint argb = unchecked((uint)BitConverter.ToInt32(cursor.Data, i));
2014-04-30 07:06:18 +00:00
if (BitConverter.IsLittleEndian)
{
argb =
(argb & 0x000000FFu) << 24 |
(argb & 0x0000FF00u) << 8 |
(argb & 0x00FF0000u) >> 8 |
(argb & 0xFF000000u) >> 24;
}
Marshal.WriteInt32(data, i, unchecked((int)argb));
i += 4;
2014-04-27 17:45:20 +00:00
}
2014-04-27 08:56:08 +00:00
}
2014-04-30 06:38:19 +00:00
// Construct the actual NSImage
IntPtr img =
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(NSImage, Selector.Alloc),
selInitWithSize,
new SizeF(cursor.Width, cursor.Height)),
Selector.Autorelease);
if (img == IntPtr.Zero)
{
Debug.Print("Failed to construct NSImage from NSBitmapImageRep");
return IntPtr.Zero;
}
Cocoa.SendVoid(img, selAddRepresentation, imgdata);
// Convert the NSImage to a NSCursor
IntPtr nscursor =
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(NSCursor, Selector.Alloc),
selInitWithImageHotSpot,
img,
new PointF(cursor.X, cursor.Y)
),
Selector.Autorelease);
return nscursor;
}
void ResetCursorRects(IntPtr sender, IntPtr cmd)
{
// We will add a new cursor rectangle that covers the complete view
var rect = Cocoa.SendRect(windowInfo.ViewHandle, selBounds);
// Inside this rectangle, the following NSCursor will be used
var cursor = IntPtr.Zero;
if (selectedCursor == MouseCursor.Default)
{
cursor = Cocoa.SendIntPtr(NSCursor, selArrowCursor);
}
else
{
cursor = ToNSCursor(selectedCursor);
}
// Setup the cursor rectangle
if (cursor != IntPtr.Zero)
{
Cocoa.SendVoid(sender, selAddCursorRect, rect, cursor);
}
}
void InvalidateCursorRects()
{
Cocoa.SendVoid(windowInfo.Handle, selInvalidateCursorRectsForView, windowInfo.ViewHandle);
2014-04-27 08:56:08 +00:00
}
2014-04-18 20:30:50 +00:00
public bool CursorVisible
{
2014-04-20 08:08:44 +00:00
get { return cursorVisible; }
2014-04-18 20:30:50 +00:00
set
{
2014-04-20 08:08:44 +00:00
cursorVisible = value;
if (value)
{
SetCursorVisible(true);
}
else
{
SetCursorVisible(false);
}
2014-04-18 20:30:50 +00:00
}
}
public void Dispose()
{
2014-04-20 08:08:44 +00:00
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
Debug.Print("Disposing of CocoaNativeWindow.");
NSApplication.Quit -= ApplicationQuit;
2014-04-20 08:08:44 +00:00
CursorVisible = true;
disposed = true;
exists = false;
if (disposing)
{
if (trackingArea != IntPtr.Zero)
{
Cocoa.SendVoid(windowInfo.ViewHandle, selRemoveTrackingArea, trackingArea);
Cocoa.SendVoid(trackingArea, Selector.Release);
trackingArea = IntPtr.Zero;
}
Cocoa.SendVoid(windowInfo.Handle, Selector.Release);
}
Disposed(this, EventArgs.Empty);
}
~CocoaNativeWindow()
{
Dispose(false);
}
private RectangleF GetContentViewFrame()
{
return Cocoa.SendRect(windowInfo.ViewHandle, selFrame);
}
2014-04-20 08:08:44 +00:00
private IntPtr GetCurrentScreen()
{
return Cocoa.SendIntPtr(windowInfo.Handle, selScreen);
}
2014-04-18 20:30:50 +00:00
2014-04-20 08:08:44 +00:00
private RectangleF GetCurrentScreenFrame()
{
return Cocoa.SendRect(GetCurrentScreen(), selFrame);
}
private RectangleF GetCurrentScreenVisibleFrame()
{
return Cocoa.SendRect(GetCurrentScreen(), selVisibleFrame);
}
2014-04-20 08:08:44 +00:00
private void SetCursorVisible(bool visible)
{
2014-04-27 17:45:20 +00:00
Carbon.CG.AssociateMouseAndMouseCursorPosition(visible);
2014-04-20 08:08:44 +00:00
Cocoa.SendVoid(NSCursor, visible ? selUnhide : selHide);
2014-04-18 20:30:50 +00:00
}
2014-04-20 17:56:23 +00:00
2014-04-27 17:45:20 +00:00
private void SetCursor(MouseCursor cursor)
{
if (cursor == MouseCursor.Default)
{
Cocoa.SendVoid(NSCursor, selUnhide);
}
else if (cursor == MouseCursor.Empty)
{
Cocoa.SendVoid(NSCursor, selHide);
}
else
{
}
}
2014-04-20 17:56:23 +00:00
private void SetMenuVisible(bool visible)
{
var options = (NSApplicationPresentationOptions)Cocoa.SendInt(NSApplication.Handle, selPresentationOptions);
var changedOptions = NSApplicationPresentationOptions.HideMenuBar | NSApplicationPresentationOptions.HideDock;
if (!visible)
{
options |= changedOptions;
}
else
{
options &= ~changedOptions;
}
Cocoa.SendVoid(NSApplication.Handle, selSetPresentationOptions, (int)options);
}
private void SetTitle(string newTitle, bool callEvent)
{
2014-04-20 20:26:26 +00:00
title = newTitle ?? "";
Cocoa.SendIntPtr(windowInfo.Handle, selSetTitle, Cocoa.ToNSString(title));
2014-04-20 17:56:23 +00:00
if (callEvent)
{
TitleChanged(this, EventArgs.Empty);
}
}
2014-04-20 20:26:26 +00:00
private void UpdateWindowBorder()
{
Cocoa.SendVoid(windowInfo.Handle, selSetStyleMask, (uint)GetStyleMask(windowBorder));
SetTitle(title, false); // Title gets lost after going borderless
}
private NSWindowStyle GetStyleMask()
{
return (NSWindowStyle)Cocoa.SendUint(windowInfo.Handle, selStyleMask);
}
2014-04-18 20:30:50 +00:00
}
}