/******************************************************************************* * Copyright (c) 2003, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.browser; import java.util.Hashtable; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.Browser; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.carbon.*; import org.eclipse.swt.internal.cocoa.*; import org.eclipse.swt.internal.mozilla.*; import org.eclipse.swt.widgets.*; class MozillaDelegate { Browser browser; int embedHandle; Listener listener; boolean hasFocus; static Callback Callback3; static Hashtable handles = new Hashtable (); MozillaDelegate (Browser browser) { super (); this.browser = browser; } static Browser findBrowser (int handle) { LONG value = (LONG)handles.get (new LONG (handle)); if (value != null) { Display display = Display.getCurrent (); return (Browser)display.findWidget (value.value); } return null; } static String getCacheParentPath () { return getProfilePath (); } static String getLibraryName () { return "libxpcom.dylib"; //$NON-NLS-1$ } static String[] getJSLibraryNames () { return new String[] {"libxpcom.dylib"}; //$NON-NLS-1$ } static String getJSLibraryName_Pre4 () { return "libmozjs.dylib"; //$NON-NLS-1$ } static String getProfilePath () { String baseDir = System.getProperty ("user.home"); //$NON-NLS-1$ return baseDir + Mozilla.SEPARATOR_OS + ".mozilla" + Mozilla.SEPARATOR_OS + "eclipse"; //$NON-NLS-1$ //$NON-NLS-2$ } static String getSWTInitLibraryName () { return "swt-xulrunner"; //$NON-NLS-1$ } static void loadAdditionalLibraries (String mozillaPath) { // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=727616 // String utilsPath = mozillaPath + Mozilla.SEPARATOR_OS + "libmozutils.dylib"; //$NON-NLS-1$ // byte[] bytes = MozillaDelegate.wcsToMbcs (null, utilsPath, true); // OS.NSAddImage (bytes, OS.NSADDIMAGE_OPTION_RETURN_ON_ERROR | OS.NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME); } static char[] mbcsToWcs (String codePage, byte [] buffer) { int encoding = OS.CFStringGetSystemEncoding (); int cfstring = OS.CFStringCreateWithBytes (OS.kCFAllocatorDefault, buffer, buffer.length, encoding, false); char[] chars = null; if (cfstring != 0) { int length = OS.CFStringGetLength (cfstring); chars = new char [length]; if (length != 0) { CFRange range = new CFRange (); range.length = length; OS.CFStringGetCharacters (cfstring, range, chars); } OS.CFRelease (cfstring); } return chars; } static boolean needsSpinup () { return false; } static boolean supportsXULRunner17 () { return false; } static byte[] wcsToMbcs (String codePage, String string, boolean terminate) { char[] chars = new char [string.length()]; string.getChars (0, chars.length, chars, 0); int cfstring = OS.CFStringCreateWithCharacters (OS.kCFAllocatorDefault, chars, chars.length); byte[] buffer = null; if (cfstring != 0) { CFRange range = new CFRange (); range.length = chars.length; int encoding = OS.CFStringGetSystemEncoding (); int[] size = new int[1]; int numChars = OS.CFStringGetBytes (cfstring, range, encoding, (byte)'?', true, null, 0, size); buffer = new byte [size[0] + (terminate ? 1 : 0)]; if (numChars != 0) { numChars = OS.CFStringGetBytes (cfstring, range, encoding, (byte)'?', true, buffer, size[0], size); } OS.CFRelease (cfstring); } return buffer; } static int eventProc3 (int nextHandler, int theEvent, int userData) { Widget widget = Display.getCurrent ().findWidget (userData); if (widget instanceof Browser) { Browser browser = (Browser) widget; switch (OS.GetEventClass (theEvent)) { case OS.kEventClassMouse: browser.getShell ().forceActive (); ((Mozilla)browser.webBrowser).Activate (); break; case OS.kEventClassKeyboard: /* * Bug in Carbon. OSX crashes if a HICocoaView is disposed during a key event, * presumably as a result of attempting to use it after its refcount has reached * 0. The workaround is to temporarily add an extra ref to the view while the * DOM listener is handling the event, in case the Browser gets disposed in a * callback. */ int result = OS.noErr; int handle = browser.handle; OS.CFRetain (handle); /* * Pressing the OSX shortcut to put focus into the menu bar does not work in * embedded mozilla. If this shortcut is not handled here then it falls through * all of the key handlers for some reason. The workaround is to detect this * shortcut here and put focus into the menu bar. */ int [] modifiers = new int [1]; OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, modifiers.length * 4, null, modifiers); int [] keyCode = new int [1]; OS.GetEventParameter (theEvent, OS.kEventParamKeyCode, OS.typeUInt32, null, keyCode.length * 4, null, keyCode); if (keyCode [0] == 120 /* F2 */ && (modifiers[0] & (OS.controlKey | OS.cmdKey | OS.optionKey)) == OS.controlKey) { int[] event = new int[1]; OS.CreateEvent (0, OS.kEventClassApplication, OS.kEventAppFocusMenuBar, 0.0, 0, event); if (event [0] != 0) { OS.SetEventParameter (event [0], OS.kEventParamKeyModifiers, OS.typeUInt32, 4, modifiers); result = OS.SendEventToEventTarget (event [0], OS.GetApplicationEventTarget ()); OS.ReleaseEvent (event [0]); } } else { result = OS.CallNextEventHandler (nextHandler, theEvent); } OS.CFRelease (handle); return result; } } return OS.eventNotHandledErr; } void addWindowSubclass () { } int createBaseWindow (nsIBaseWindow baseWindow) { /* * Feature of Mozilla on OSX. Mozilla replaces the OSX application menu whenever * a browser's base window is created. The workaround is to restore the previous * menu after creating the base window. */ int application = Cocoa.objc_msgSend (Cocoa.C_NSApplication, Cocoa.S_sharedApplication); int mainMenu = Cocoa.objc_msgSend (application, Cocoa.S_mainMenu); if (mainMenu != 0) { Cocoa.objc_msgSend (mainMenu, Cocoa.S_retain); } int rc = baseWindow.Create (); if (mainMenu != 0) { Cocoa.objc_msgSend (application, Cocoa.S_setMainMenu, mainMenu); Cocoa.objc_msgSend (mainMenu, Cocoa.S_release); } return rc; } int getHandle () { embedHandle = Cocoa.objc_msgSend (Cocoa.C_NSImageView, Cocoa.S_alloc); if (embedHandle == 0) { browser.dispose (); SWT.error (SWT.ERROR_NO_HANDLES); } NSRect r = new NSRect (); embedHandle = Cocoa.objc_msgSend (embedHandle, Cocoa.S_initWithFrame, r); int rc; int[] outControl = new int[1]; rc = Cocoa.HICocoaViewCreate (embedHandle, 0, outControl); /* OSX >= 10.5 */ if (rc == OS.noErr && outControl[0] != 0) { Cocoa.objc_msgSend (embedHandle, Cocoa.S_release); } else { /* will succeed on OSX 10.4 with an updated vm containing HIJavaViewCreateWithCocoaView */ try { System.loadLibrary ("frameembedding"); //$NON-NLS-1$ } catch (UnsatisfiedLinkError e) {} rc = Cocoa.HIJavaViewCreateWithCocoaView (outControl, embedHandle); if (!(rc == OS.noErr && outControl[0] != 0)) { browser.dispose (); SWT.error (SWT.ERROR_NO_HANDLES); } } int subHIView = outControl[0]; HILayoutInfo newLayoutInfo = new HILayoutInfo (); newLayoutInfo.version = 0; OS.HIViewGetLayoutInfo (subHIView, newLayoutInfo); HISideBinding biding = newLayoutInfo.binding.top; biding.toView = 0; biding.kind = OS.kHILayoutBindMin; biding.offset = 0; biding = newLayoutInfo.binding.left; biding.toView = 0; biding.kind = OS.kHILayoutBindMin; biding.offset = 0; biding = newLayoutInfo.binding.bottom; biding.toView = 0; biding.kind = OS.kHILayoutBindMax; biding.offset = 0; biding = newLayoutInfo.binding.right; biding.toView = 0; biding.kind = OS.kHILayoutBindMax; biding.offset = 0; OS.HIViewSetLayoutInfo (subHIView, newLayoutInfo); OS.HIViewChangeFeatures (subHIView, OS.kHIViewFeatureIsOpaque, 0); OS.HIViewSetVisible (subHIView, true); int parentHandle = browser.handle; OS.HIViewAddSubview (browser.handle, subHIView); CGRect rect = new CGRect (); OS.HIViewGetFrame (parentHandle, rect); rect.x = rect.y = 0; OS.HIViewSetFrame (subHIView, rect); handles.put (new LONG (embedHandle), new LONG (browser.handle)); if (Callback3 == null) Callback3 = new Callback (this.getClass (), "eventProc3", 3); //$NON-NLS-1$ int callback3Address = Callback3.getAddress (); if (callback3Address == 0) { browser.dispose (); SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); } int [] mask = new int [] { OS.kEventClassMouse, OS.kEventMouseDown, OS.kEventClassKeyboard, OS.kEventRawKeyDown, }; int controlTarget = OS.GetControlEventTarget (subHIView); OS.InstallEventHandler (controlTarget, callback3Address, mask.length / 2, mask, browser.handle, null); return embedHandle; } long /*int*/ getSiteWindow () { return embedHandle; } void handleFocus () { if (hasFocus) return; hasFocus = true; ((Mozilla)browser.webBrowser).Activate (); browser.setFocus (); listener = new Listener () { public void handleEvent (Event event) { if (event.widget == browser) return; ((Mozilla)browser.webBrowser).Deactivate (); hasFocus = false; browser.getDisplay ().removeFilter (SWT.FocusIn, this); browser.getShell ().removeListener (SWT.Deactivate, this); listener = null; } }; browser.getDisplay ().addFilter (SWT.FocusIn, listener); browser.getShell ().addListener (SWT.Deactivate, listener); } void handleMouseDown () { } boolean hookEnterExit () { return true; } void init () { } void onDispose (int embedHandle) { handles.remove (new LONG (embedHandle)); if (listener != null) { browser.getDisplay ().removeFilter (SWT.FocusIn, listener); browser.getShell ().removeListener (SWT.Deactivate, listener); listener = null; } browser = null; } void removeWindowSubclass () { } boolean sendTraverse () { return true; } void setSize (int embedHandle, int width, int height) { // TODO } }