2014-04-23 18:15:09 +00:00
|
|
|
|
#region License
|
|
|
|
|
//
|
|
|
|
|
// NSApplication.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-28 14:19:04 +00:00
|
|
|
|
using System.ComponentModel;
|
2014-07-23 19:14:47 +00:00
|
|
|
|
using System.Diagnostics;
|
2014-04-18 20:30:50 +00:00
|
|
|
|
using System.Runtime.InteropServices;
|
2014-07-23 19:14:47 +00:00
|
|
|
|
using System.Threading;
|
2014-04-18 20:30:50 +00:00
|
|
|
|
using OpenTK.Platform.MacOS;
|
|
|
|
|
|
|
|
|
|
namespace OpenTK.Platform.MacOS
|
|
|
|
|
{
|
|
|
|
|
static class NSApplication
|
|
|
|
|
{
|
|
|
|
|
internal static IntPtr Handle;
|
|
|
|
|
|
2014-04-28 14:19:04 +00:00
|
|
|
|
static readonly IntPtr selQuit = Selector.Get("quit");
|
|
|
|
|
|
2014-07-23 19:14:47 +00:00
|
|
|
|
static readonly int ThreadId =
|
|
|
|
|
System.Threading.Thread.CurrentThread.ManagedThreadId;
|
|
|
|
|
|
2014-07-23 12:35:51 +00:00
|
|
|
|
internal static void Initialize() { }
|
|
|
|
|
|
|
|
|
|
static NSApplication()
|
2014-04-18 20:30:50 +00:00
|
|
|
|
{
|
2014-07-23 12:35:51 +00:00
|
|
|
|
Cocoa.Initialize();
|
|
|
|
|
|
2014-04-28 14:19:04 +00:00
|
|
|
|
// Register a Quit method to be called on cmd-q
|
|
|
|
|
IntPtr nsapp = Class.Get("NSApplication");
|
2014-07-23 08:10:08 +00:00
|
|
|
|
Class.RegisterMethod(nsapp, OnQuitHandler, "quit", "v@:");
|
2014-04-28 14:19:04 +00:00
|
|
|
|
|
2014-04-18 20:30:50 +00:00
|
|
|
|
// Fetch the application handle
|
2014-04-28 14:19:04 +00:00
|
|
|
|
Handle = Cocoa.SendIntPtr(nsapp, Selector.Get("sharedApplication"));
|
2014-04-18 20:30:50 +00:00
|
|
|
|
|
|
|
|
|
// Setup the application
|
|
|
|
|
Cocoa.SendBool(Handle, Selector.Get("setActivationPolicy:"), (int)NSApplicationActivationPolicy.Regular);
|
|
|
|
|
Cocoa.SendVoid(Handle, Selector.Get("activateIgnoringOtherApps:"), true);
|
|
|
|
|
|
2014-09-11 10:07:53 +00:00
|
|
|
|
if (Cocoa.SendIntPtr(Handle, Selector.Get("mainMenu")) == IntPtr.Zero)
|
|
|
|
|
{
|
|
|
|
|
// Create the menu bar
|
|
|
|
|
var menubar = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
|
|
|
|
|
var menuItem = Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc);
|
2014-04-18 20:30:50 +00:00
|
|
|
|
|
2014-09-11 10:07:53 +00:00
|
|
|
|
// Add menu item to bar, and bar to application
|
|
|
|
|
Cocoa.SendIntPtr(menubar, Selector.Get("addItem:"), menuItem);
|
|
|
|
|
Cocoa.SendIntPtr(Handle, Selector.Get("setMainMenu:"), menubar);
|
2014-04-21 17:41:45 +00:00
|
|
|
|
|
2014-09-11 10:07:53 +00:00
|
|
|
|
// Add a "Quit" menu item and bind the button.
|
|
|
|
|
var appMenu = Cocoa.SendIntPtr(Class.Get("NSMenu"), Selector.Alloc);
|
|
|
|
|
var quitMenuItem = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSMenuItem"), Selector.Alloc),
|
|
|
|
|
Selector.Get("initWithTitle:action:keyEquivalent:"), Cocoa.ToNSString("Quit"), selQuit, Cocoa.ToNSString("q"));
|
2014-04-27 08:52:28 +00:00
|
|
|
|
|
2014-09-11 10:07:53 +00:00
|
|
|
|
Cocoa.SendIntPtr(appMenu, Selector.Get("addItem:"), quitMenuItem);
|
|
|
|
|
Cocoa.SendIntPtr(menuItem, Selector.Get("setSubmenu:"), appMenu);
|
2014-04-27 08:52:28 +00:00
|
|
|
|
|
2014-09-11 10:21:05 +00:00
|
|
|
|
// Tell cocoa we're ready to run the application (usually called by [NSApp run]).
|
|
|
|
|
// Note: if a main menu exists, then this method has already been called and
|
|
|
|
|
// calling it again will result in a crash. For this reason, we only call it
|
|
|
|
|
// when we create our own main menu.
|
|
|
|
|
Cocoa.SendVoid(Handle, Selector.Get("finishLaunching"));
|
|
|
|
|
}
|
2014-05-04 13:23:24 +00:00
|
|
|
|
|
|
|
|
|
// Disable momentum scrolling and long-press key pop-ups
|
|
|
|
|
IntPtr settings = Cocoa.SendIntPtr(Class.NSDictionary, Selector.Alloc);
|
2014-07-21 15:46:39 +00:00
|
|
|
|
//IntPtr momentum_scrolling = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
|
2014-05-04 13:23:24 +00:00
|
|
|
|
IntPtr press_and_hold = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
|
|
|
|
|
|
|
|
|
|
// Initialize and register the settings dictionary
|
|
|
|
|
settings =
|
|
|
|
|
Cocoa.SendIntPtr(settings, Selector.Get("initWithObjectsAndKeys:"),
|
2014-05-10 15:54:34 +00:00
|
|
|
|
//momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"),
|
2014-05-04 13:23:24 +00:00
|
|
|
|
press_and_hold, Cocoa.ToNSString("ApplePressAndHoldEnabled"),
|
|
|
|
|
IntPtr.Zero);
|
|
|
|
|
Cocoa.SendVoid(
|
|
|
|
|
Cocoa.SendIntPtr(Class.NSUserDefaults, Selector.Get("standardUserDefaults")),
|
|
|
|
|
Selector.Get("registerDefaults:"),
|
|
|
|
|
settings);
|
|
|
|
|
Cocoa.SendVoid(settings, Selector.Release);
|
2014-04-18 20:30:50 +00:00
|
|
|
|
}
|
2014-04-28 14:19:04 +00:00
|
|
|
|
|
2014-07-23 19:14:47 +00:00
|
|
|
|
internal static bool IsUIThread
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
int thread_id = Thread.CurrentThread.ManagedThreadId;
|
|
|
|
|
bool is_ui_thread = thread_id == NSApplication.ThreadId;
|
|
|
|
|
if (!is_ui_thread)
|
|
|
|
|
{
|
|
|
|
|
Debug.Print("[Warning] UI resources must be disposed in the UI thread #{0}, not #{1}.",
|
|
|
|
|
NSApplication.ThreadId, thread_id);
|
|
|
|
|
}
|
|
|
|
|
return is_ui_thread;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-28 14:19:04 +00:00
|
|
|
|
internal static event EventHandler<CancelEventArgs> Quit = delegate { };
|
|
|
|
|
|
2014-07-23 19:14:47 +00:00
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
2014-04-28 14:19:04 +00:00
|
|
|
|
delegate void OnQuitDelegate(IntPtr self, IntPtr cmd);
|
2014-07-23 19:14:47 +00:00
|
|
|
|
|
2014-07-23 08:10:08 +00:00
|
|
|
|
static OnQuitDelegate OnQuitHandler = OnQuit;
|
2014-04-28 14:19:04 +00:00
|
|
|
|
static void OnQuit(IntPtr self, IntPtr cmd)
|
|
|
|
|
{
|
|
|
|
|
var e = new CancelEventArgs();
|
|
|
|
|
Quit(null, e);
|
|
|
|
|
if (!e.Cancel)
|
|
|
|
|
{
|
|
|
|
|
Cocoa.SendVoid(Handle, Selector.Get("terminate:"), Handle);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-04-18 20:30:50 +00:00
|
|
|
|
}
|
|
|
|
|
}
|