blob: ba33b09b198e488b956c63cd081f2e08cf116d47 [file] [log] [blame]
/*
* Copyright (c) 2002 IBM Corp. All rights reserved.
* This file is made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Andre Weinand, OTI - Initial version
*/
package org.eclipse.swt.internal.carbon;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.Callback;
public class MacUtil {
public final static boolean DEBUG;
public final static boolean USE_MENU_ICONS;
/** Prevent use of standard Mac shortcuts Cmd-Q, Cmd-H */
public final static boolean KEEP_MAC_SHORTCUTS;
public final static boolean FULL_KBD_NAV;
/** use HIViews instead of ControlManager controls */
public final static boolean HIVIEW;
/** use setFrame calls instead of setBounds */
public final static boolean USE_FRAME;
static final char MNEMONIC = '&';
static {
DEBUG= false;
USE_MENU_ICONS= true;
KEEP_MAC_SHORTCUTS= true;
FULL_KBD_NAV= true;
HIVIEW= false;
USE_FRAME= false;
}
//////////////////////////////////////////////////////////////////////
private static int fViewClassID= 0;
static int createCallback(String method, int argCount) {
Callback cb= new Callback(MacUtil.class, method, argCount);
int proc= cb.getAddress();
return proc;
}
static int hiobProc(int a, int b, int c) {
System.out.println("hiobProc");
return OS.kNoErr;
}
static int createHIView() {
int rc;
if (fViewClassID == 0) {
fViewClassID= OS.CFStringCreateWithCharacters("org.eclipse.swt.hiview");
int baseClassID= OS.CFStringCreateWithCharacters("com.apple.hiview");
int[] events= new int[] {
OS.kEventClassHIObject, OS.kEventHIObjectConstruct,
//OS.kEventClassHIObject, OS.kEventHIObjectInitialize,
OS.kEventClassHIObject, OS.kEventHIObjectDestruct,
OS.kEventClassControl, OS.kEventControlDraw,
OS.kEventClassControl, OS.kEventControlAddedSubControl,
OS.kEventClassControl, OS.kEventControlRemovingSubControl,
};
int hiobProc= createCallback("hiobProc", 3);
int[] tmp= new int[1];
rc= OS.HIObjectRegisterSubclass(fViewClassID, baseClassID, 0, hiobProc, events, 0, tmp);
System.out.println("HIObjectRegisterSubclass: " + rc);
OS.CFRelease(baseClassID);
}
int[] oref= new int[1];
//rc= OS.HIObjectCreate(fViewClassID, 0, oref);
rc= OS.HIObjectCreate(OS.CFStringCreateWithCharacters("com.apple.hiview"), 0, oref);
System.out.println("HIObjectCreate: " + rc + " " + oref[0]);
return oref[0];
}
//////////////////////////////////////////////////////////////////////
public static int getChild(int handle, int[] t, int n, int i) {
int index= (n-1 - i);
int status= OS.GetIndexedSubControl(handle, (short)(index+1), t);
if (status != OS.kNoErr)
System.out.println("MacUtil.getChild: error");
return status;
}
public static int indexOf(int parentHandle, int handle) {
int n= countSubControls(parentHandle);
int[] outControl= new int[1];
for (int i= 0; i < n; i++) {
if (getChild(parentHandle, outControl, n, i) == OS.kNoErr)
if (outControl[0] == handle)
return i;
}
return -1;
}
/**
* Inserts the given child at position in the parent.
* If pos is out of range the child is added at the end (below all other).
*/
private static void insertControl(int controlHandle, int parentControlHandle, int pos) {
int n= countSubControls(parentControlHandle);
int should= pos;
if (should < 0 || should > n)
should= n;
boolean add= false;
if (getSuperControl(controlHandle) != parentControlHandle) {
add= true;
} else {
/*
String w1= getHIObjectClassID(parentControlHandle);
String w2= getHIObjectClassID(controlHandle);
System.out.println("MacUtil.insertControl: already there: " + w1 + " " + w2);
*/
if (n == 1)
return;
}
if (n == 0) {
OS.HIViewAddSubview(parentControlHandle, controlHandle);
pos= 0;
} else {
if (pos >= 0 && pos < n) {
int[] where= new int[1];
getChild(parentControlHandle, where, n, pos);
if (add)
OS.HIViewAddSubview(parentControlHandle, controlHandle);
OS.HIViewSetZOrder(controlHandle, OS.kHIViewZOrderAbove, where[0]);
} else {
if (add)
OS.HIViewAddSubview(parentControlHandle, controlHandle);
if (OS.HIViewSetZOrder(controlHandle, OS.kHIViewZOrderBelow, 0) != OS.kNoErr)
System.out.println("error 2");
pos= n;
}
}
// verify correct position
int i= indexOf(parentControlHandle, controlHandle);
if (i != should)
System.out.println("MacUtil.insertControl: is: "+i+" should: "+ should + " n:" + n + " add: " + add);
}
/**
* Adds the given child at the end.
*/
public static void addControl(int controlHandle, int parentControlHandle) {
insertControl(controlHandle, parentControlHandle, -1);
}
public static int getVisibleRegion(int cHandle, int result, boolean includingTop) {
int tmpRgn= OS.NewRgn();
getControlRegion(cHandle, OS.kControlEntireControl, result);
int parent= cHandle;
while ((parent= MacUtil.getSuperControl(parent)) != 0) {
getControlRegion(parent, OS.kControlContentMetaPart, tmpRgn);
OS.SectRgn(result, tmpRgn, result);
}
if (includingTop) {
int n= countSubControls(cHandle);
if (n > 0) {
//System.out.println("have children on top");
int[] outHandle= new int[1];
for (int i= 0; i < n; i++) {
int index= i; // was: n-1-i
if (OS.GetIndexedSubControl(cHandle, (short)(index+1), outHandle) == 0) { // indices are 1 based
if (OS.IsControlVisible(outHandle[0])) {
getControlRegion(outHandle[0], OS.kControlStructureMetaPart, tmpRgn);
OS.DiffRgn(result, tmpRgn, result);
}
} else
throw new SWTError();
}
}
}
OS.DisposeRgn(tmpRgn);
return OS.kNoErr;
}
private static int find(int cHandle, Rectangle parentBounds, MacRect tmp, Point where) {
if (! OS.IsControlVisible(cHandle))
return 0;
if (! OS.IsControlActive(cHandle))
return 0;
OS.GetControlBounds(cHandle, tmp.getData());
Rectangle rr= tmp.toRectangle();
if (parentBounds != null)
rr= parentBounds.intersection(rr);
int n= countSubControls(cHandle);
if (n > 0) {
int[] outHandle= new int[1];
for (int i= 0; i < n; i++) {
int index= (n-1-i);
if (OS.GetIndexedSubControl(cHandle, (short)(index+1), outHandle) == 0) { // indices are 1 based
int result= find(outHandle[0], rr, tmp, where);
if (result != 0)
return result;
}
}
}
if (rr.contains(where))
return cHandle;
return 0;
}
//////////////////////////////////////////////////////////////////////
public static Point toControl(int cHandle, Point point) {
MacPoint mp= new MacPoint(point);
int wHandle= OS.GetControlOwner(cHandle);
int port= OS.GetWindowPort(wHandle);
OS.QDGlobalToLocalPoint(port, mp.getData());
MacRect bounds= new MacRect();
OS.GetControlBounds(cHandle, bounds.getData());
Point p= mp.toPoint();
p.x-= bounds.getX();
p.y-= bounds.getY();
/*
float[] p2= new float[2];
p2[0]= mp.getX();
p2[1]= mp.getY();
OS.HIViewConvertPoint(p2, 0, cHandle);
System.out.println("MacUtil.toControl: " + p + " " + p2[0] + " " + p2[1]);
*/
return p;
}
public static Point toDisplay(int cHandle, Point point) {
MacRect bounds= new MacRect();
OS.GetControlBounds(cHandle, bounds.getData());
MacPoint mp= new MacPoint(point.x+bounds.getX(), point.y+bounds.getY());
int wHandle= OS.GetControlOwner(cHandle);
int port= OS.GetWindowPort(wHandle);
OS.QDLocalToGlobalPoint(port, mp.getData());
return mp.toPoint();
}
private static void getControlRegion(int cHandle, short part, int rgn) {
if (true) {
short[] bounds= new short[4];
OS.GetControlBounds(cHandle, bounds);
OS.RectRgn(rgn, bounds);
} else {
OS.GetControlRegion(cHandle, part, rgn);
}
}
// Hit detection on the Mac is reversed and doesn't consider clipping,
// so we have to do it ourselves
public static int findControlUnderMouse(MacPoint where, int wHandle, short[] cpart) {
int root;
if (true) {
int[] rootHandle= new int[1];
int rc= OS.GetRootControl(wHandle, rootHandle);
if (rc != OS.kNoErr) {
System.out.println("MacUtil.findControlUnderMouse: " + rc);
return 0;
}
root= rootHandle[0];
} else {
root= OS.HIViewGetRoot(wHandle);
}
Point w= where.toPoint();
int cHandle= find(root, null, new MacRect(), w);
if (cHandle != 0 && cpart != null && cpart.length > 0) {
cpart[0]= OS.TestControl(cHandle, where.getData());
//System.out.println("findControlUnderMouse: " + cpart[0]);
}
return cHandle;
}
private static int countSubControls(int cHandle) {
short[] cnt= new short[1];
int status= OS.CountSubControls(cHandle, cnt);
switch (status) {
case OS.kNoErr:
return cnt[0];
case OS.errControlIsNotEmbedder:
//System.out.println("MacUtil.countSubControls: errControlIsNotEmbedder");
break;
case -30599: // OS.controlHandleInvalidErr
System.out.println("MacUtil.countSubControls: controlHandleInvalidErr");
break;
default:
System.out.println("MacUtil.countSubControls: " + status);
break;
}
return 0;
}
public static String getStringAndRelease(int sHandle) {
int length= OS.CFStringGetLength(sHandle);
char[] buffer= new char[length];
OS.CFStringGetCharacters(sHandle, 0, length, buffer);
OS.CFRelease(sHandle);
return new String(buffer);
}
public static byte[] Str255(String s) {
int l= 0;
if (s != null)
l= s.length();
if (l > 255) {
throw new SWTError(SWT.ERROR_INVALID_RANGE);
//System.out.println("MacUtil.Str255: string length > 255");
}
byte[] b= new byte[l+1];
b[0]= (byte) l;
for (int i= 0; i < l; i++)
b[i+1]= (byte) s.charAt(i);
return b;
}
public static String toString(byte[] str255) {
int n= str255[0];
char[] c= new char[n];
for (int i= 0; i < n; i++)
c[i]= (char) str255[i+1];
return new String(c);
}
public static int OSType(String s) {
return ((s.charAt(0) & 0xff) << 24) | ((s.charAt(1) & 0xff) << 16) | ((s.charAt(2) & 0xff) << 8) | (s.charAt(3) & 0xff);
}
public static String getHIObjectClassID(int handle) {
int sh= OS.HIObjectCopyClassID(handle);
return getStringAndRelease(sh);
}
/**
* Create a new control and embed it in the given parent control.
*/
public static int newControl(int parentControlHandle, short procID) {
return newControl(parentControlHandle, -1, (short)0, (short)0, (short)0, procID);
}
/**
* Create a new control and embed it in the given parent control.
*/
public static int newControl(int parentControlHandle, short init, short min, short max, short procID) {
return newControl(parentControlHandle, -1, init, min, max, procID);
}
/**
* Create a new control and embed it in the given parent control.
*/
public static int newControl(int parentControlHandle, int pos, short init, short min, short max, short procID) {
int controlHandle;
if (HIVIEW) {
controlHandle= OS.NewControl(0, false, init, min, max, procID);
insertControl(controlHandle, parentControlHandle, pos);
OS.HIViewSetVisible(controlHandle, true);
OS.HIViewSetNeedsDisplay(controlHandle, true);
} else {
int windowHandle= OS.GetControlOwner(parentControlHandle);
controlHandle= OS.NewControl(windowHandle, false, init, min, max, procID);
insertControl(controlHandle, parentControlHandle, pos);
initLocation(controlHandle);
OS.HIViewSetVisible(controlHandle, true);
}
return controlHandle;
}
public static int createDrawingArea(int parentControlHandle, int pos, boolean visible, int width, int height, int border) {
int features= OS.kControlSupportsEmbedding | OS.kControlSupportsFocus | OS.kControlGetsFocusOnClick;
int controlHandle;
if (HIVIEW) {
features |= OS.kControlHandlesTracking;
controlHandle= OS.NewControl(0, false, (short)features, (short)0, (short)0, OS.kControlUserPaneProc);
OS.SizeControl(controlHandle, (short)width, (short)height);
insertControl(controlHandle, parentControlHandle, pos);
OS.HIViewSetVisible(controlHandle, visible);
OS.HIViewSetNeedsDisplay(controlHandle, true);
} else {
int windowHandle= OS.GetControlOwner(parentControlHandle);
controlHandle= OS.NewControl(windowHandle, false, (short)features, (short)0, (short)0, OS.kControlUserPaneProc);
OS.SizeControl(controlHandle, (short)width, (short)height);
insertControl(controlHandle, parentControlHandle, pos);
initLocation(controlHandle);
OS.HIViewSetVisible(controlHandle, visible);
}
return controlHandle;
}
public static void initLocation(int cHandle) {
int parent= getSuperControl(cHandle);
short[] bounds= new short[4];
OS.GetControlBounds(parent, bounds);
short x= bounds[1];
short y= bounds[0];
if (x > 0 || y > 0)
OS.MoveControl(cHandle, x, y);
}
/**
* Returns the parent of the given control or null if the control is a root control.
*/
public static int getSuperControl(int cHandle) {
int wHandle= OS.GetControlOwner(cHandle);
if (wHandle == 0) {
//System.out.println("MacUtil.getSuperControl: GetControlOwner error");
return 0;
}
int[] rootHandle= new int[1];
OS.GetRootControl(wHandle, rootHandle);
if (cHandle == rootHandle[0])
return 0;
int[] parentHandle= new int[1];
int rc= OS.GetSuperControl(cHandle, parentHandle);
if (rc != OS.kNoErr)
System.out.println("MacUtil.getSuperControl: " + rc);
return parentHandle[0];
}
public static void dump(int matchHandle) {
int wHandle= OS.GetControlOwner(matchHandle);
int[] rootHandle= new int[1];
OS.GetRootControl(wHandle, rootHandle);
dump(rootHandle[0], 0, matchHandle);
System.out.println();
}
public static void dump(int cHandle, int level, int matchHandle) {
for (int x= 0; x < level; x++)
System.out.print(" ");
Widget w= WidgetTable.get(cHandle);
if (w != null)
System.out.print(w);
else
System.out.print(cHandle);
MacRect bounds= new MacRect();
OS.GetControlBounds(cHandle, bounds.getData());
System.out.print(" " + bounds.toRectangle());
if (cHandle == matchHandle)
System.out.println(" ******************");
else
System.out.println();
int n= countSubControls(cHandle);
if (n > 0) {
int[] outHandle= new int[1];
for (int i= 0; i < n; i++) {
if (OS.GetIndexedSubControl(cHandle, (short)(i+1), outHandle) == 0)
dump(outHandle[0], level+1, matchHandle);
}
}
}
public static Point computeSize(int handle) {
if (OS.IsValidControlHandle(handle)) {
MacRect rect= new MacRect();
short[] base= new short[1];
OS.GetBestControlRect(handle, rect.getData(), base);
if (rect.isEmpty())
System.out.println("MacUtil.computeSize: 0 size");
return rect.getSize();
}
System.out.println("MacUtil.computeSize: unknown handle type");
return new Point(50, 50);
}
public static int getDisplayWidth() {
MacRect bounds= new MacRect();
OS.GetAvailableWindowPositioningBounds(OS.GetMainDevice(), bounds.getData());
return bounds.getWidth();
}
public static int getDisplayHeight() {
MacRect bounds= new MacRect();
OS.GetAvailableWindowPositioningBounds(OS.GetMainDevice(), bounds.getData());
return bounds.getHeight();
}
public static String toString(int i) {
StringBuffer sb= new StringBuffer();
sb.append((char)((i & 0xff000000) >> 24));
sb.append((char)((i & 0x00ff0000) >> 16));
sb.append((char)((i & 0x0000ff00) >> 8));
sb.append((char)((i & 0x000000ff) >> 0));
return sb.toString();
}
public static String removeMnemonics(String s) {
if (s != null) {
int l= s.length();
if (l > 0) {
char[] buf= new char[l];
int j= 0;
for (int i= 0; i < l; i++) {
char c= s.charAt(i);
if (c != MNEMONIC)
buf[j++]= c;
}
return new String(buf, 0, j);
}
}
return s;
}
public static void RGBBackColor(int packed) {
if ((packed & 0xff000000) == 0) {
OS.RGBBackColor((short)(((packed >> 16) & 0xFF) * 257),
(short)(((packed >> 8) & 0xFF) * 257),
(short)(((packed) & 0xFF) * 257));
} else {
OS.RGBBackColor((short)0xFFFF, (short)0xFFFF, (short)0xFFFF);
}
}
public static void RGBForeColor(int packed) {
if ((packed & 0xff000000) == 0) {
OS.RGBForeColor((short)(((packed >> 16) & 0xFF) * 257),
(short)(((packed >> 8) & 0xFF) * 257),
(short)(((packed) & 0xFF) * 257));
} else {
OS.RGBForeColor((short)0xFFFF, (short)0xFFFF, (short)0xFFFF);
}
}
public static int[] getDataBrowserItems(int dataBrowserHandle, int containerID, int state, boolean recurse) {
int resultHandle= 0;
try {
resultHandle= OS.NewHandle(0);
if (OS.GetDataBrowserItems(dataBrowserHandle, containerID, recurse, state, resultHandle) == OS.kNoErr) {
int itemCount= OS.GetHandleSize(resultHandle) / 4; // sizeof(int)
if (itemCount > 0) {
int resultIDs[]= new int[itemCount];
OS.getHandleData(resultHandle, resultIDs);
return resultIDs;
}
}
} finally {
OS.DisposeHandle(resultHandle);
}
return new int[0];
}
public static int[] getSelectionIDs(int dataBrowserHandle, int containerID, boolean recurse) {
return getDataBrowserItems(dataBrowserHandle, containerID, OS.kDataBrowserItemIsSelected, recurse);
}
}