blob: a8c6c2e872e767228e65a4b5f37439be4c529d7c [file] [log] [blame]
/*
* Copyright (c) 2014 Eike Stepper (Loehne, Germany) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.oomph.setup.internal.installer;
import org.eclipse.oomph.util.ReflectUtil;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.widgets.Display;
import java.lang.reflect.Method;
/**
* @author Eike Stepper
*/
@SuppressWarnings("nls")
public final class CocoaUtil
{
private static final int ABOUT_ITEM_INDEX = 0;
private static final int PREFERENCES_ITEM_INDEX = 2;
private static final int QUIT_ITEM_INDEX = 10;
private static final String TYPES = "@:@";
private static Object invoke(Method method, Object target, Object... arguments)
{
return ReflectUtil.invokeMethod(method, target, arguments);
}
public static void register(Display display, final Runnable about, final Runnable preferences, final Runnable quit)
{
try
{
final Class<?> NSString = Class.forName("org.eclipse.swt.internal.cocoa.NSString");
final Method NSString_stringWith = ReflectUtil.getMethod(NSString, "stringWith", String.class);
final Class<?> Callback = Class.forName("org.eclipse.swt.internal.Callback");
final Method Callback_getAddress = ReflectUtil.getMethod(Callback, "getAddress");
final Method Callback_dispose = ReflectUtil.getMethod(Callback, "dispose");
final Class<?> OS = Class.forName("org.eclipse.swt.internal.cocoa.OS");
final Method OS_sel_registerName = ReflectUtil.getMethod(OS, "sel_registerName", String.class);
final Method OS_objc_lookUpClass = ReflectUtil.getMethod(OS, "objc_lookUpClass", String.class);
final Method OS_class_addMethod = ReflectUtil.getMethod(OS, "class_addMethod", long.class, long.class, long.class, String.class);
final Class<?> NSApplication = Class.forName("org.eclipse.swt.internal.cocoa.NSApplication");
final Method NSApplication_sharedApplication = ReflectUtil.getMethod(NSApplication, "sharedApplication");
final Method NSApplication_mainMenu = ReflectUtil.getMethod(NSApplication, "mainMenu");
final Class<?> NSMenu = Class.forName("org.eclipse.swt.internal.cocoa.NSMenu");
final Method NSMenu_itemAtIndex = ReflectUtil.getMethod(NSMenu, "itemAtIndex", long.class);
final Class<?> NSMenuItem = Class.forName("org.eclipse.swt.internal.cocoa.NSMenuItem");
final Method NSMenuItem_submenu = ReflectUtil.getMethod(NSMenuItem, "submenu");
final Method NSMenuItem_setTitle = ReflectUtil.getMethod(NSMenuItem, "setTitle", NSString);
final Method NSMenuItem_setEnabled = ReflectUtil.getMethod(NSMenuItem, "setEnabled", boolean.class);
final Method NSMenuItem_setAction = ReflectUtil.getMethod(NSMenuItem, "setAction", long.class);
final long aboutItemSelected = (Long)invoke(OS_sel_registerName, null, "aboutMenuItemSelected:");
final long preferencesItemSelected = (Long)invoke(OS_sel_registerName, null, "preferencesMenuItemSelected:");
final long quitItemSelected = (Long)invoke(OS_sel_registerName, null, "quitMenuItemSelected:");
Object callbackTarget = new Object()
{
@SuppressWarnings("unused")
long actionProc(long id, long sel, long arg2)
{
if (sel == aboutItemSelected)
{
if (about != null)
{
about.run();
}
}
else if (sel == preferencesItemSelected)
{
if (preferences != null)
{
preferences.run();
}
}
else if (sel == quitItemSelected)
{
if (quit != null)
{
quit.run();
}
}
return 0;
}
};
@SuppressWarnings("restriction")
final org.eclipse.swt.internal.Callback callback = new org.eclipse.swt.internal.Callback(callbackTarget, "actionProc", 3);
final long callbackPointer = (Long)invoke(Callback_getAddress, callback);
if (callbackPointer == 0)
{
throw new SWTException("No more callbacks");
}
final long classPointer = (Long)invoke(OS_objc_lookUpClass, null, "SWTApplicationDelegate");
invoke(OS_class_addMethod, null, classPointer, aboutItemSelected, callbackPointer, TYPES);
invoke(OS_class_addMethod, null, classPointer, preferencesItemSelected, callbackPointer, TYPES);
invoke(OS_class_addMethod, null, classPointer, quitItemSelected, callbackPointer, TYPES);
final Object application = invoke(NSApplication_sharedApplication, null);
final Object mainMenu = invoke(NSApplication_mainMenu, application);
final Object mainItem = invoke(NSMenu_itemAtIndex, mainMenu, (long)0);
final Object appMenu = invoke(NSMenuItem_submenu, mainItem);
final Object aboutItem = invoke(NSMenu_itemAtIndex, appMenu, (long)ABOUT_ITEM_INDEX);
final Object preferencesItem = invoke(NSMenu_itemAtIndex, appMenu, (long)PREFERENCES_ITEM_INDEX);
final Object quitItem = invoke(NSMenu_itemAtIndex, appMenu, (long)QUIT_ITEM_INDEX);
final String appName = Display.getAppName();
if (appName != null)
{
final Object aboutLabel = invoke(NSString_stringWith, null, "About " + appName);
invoke(NSMenuItem_setTitle, aboutItem, aboutLabel);
final Object quitLabel = invoke(NSString_stringWith, null, "Quit " + appName);
invoke(NSMenuItem_setTitle, quitItem, quitLabel);
}
invoke(NSMenuItem_setAction, aboutItem, aboutItemSelected);
invoke(NSMenuItem_setAction, preferencesItem, preferencesItemSelected);
invoke(NSMenuItem_setAction, quitItem, quitItemSelected);
invoke(NSMenuItem_setEnabled, preferencesItem, true);
invoke(NSMenuItem_setEnabled, quitItem, true);
display.disposeExec(new Runnable()
{
@Override
public void run()
{
invoke(Callback_dispose, callback);
}
});
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}