Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT Browser')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Browser/carbon/org/eclipse/swt/browser/Safari.java2082
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Browser/cocoa/org/eclipse/swt/browser/Safari.java1572
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationEvent.java69
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationListener.java56
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/Browser.java992
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/BrowserFunction.java192
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/CloseWindowListener.java49
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationAdapter.java33
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationEvent.java71
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationListener.java65
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/OpenWindowListener.java60
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressAdapter.java33
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressEvent.java58
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressListener.java63
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextEvent.java55
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextListener.java45
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleEvent.java54
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleListener.java45
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowAdapter.java33
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowListener.java91
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java598
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WindowEvent.java218
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/package.html15
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/forms/org/eclipse/swt/browser/IE.java280
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT Browser/photon/org/eclipse/swt/browser/Voyager.java469
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/IE.java1440
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/WebSite.java921
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT Browser/wpf/org/eclipse/swt/browser/IE.java220
28 files changed, 9879 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/carbon/org/eclipse/swt/browser/Safari.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/carbon/org/eclipse/swt/browser/Safari.java
new file mode 100755
index 0000000000..ec720be249
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/carbon/org/eclipse/swt/browser/Safari.java
@@ -0,0 +1,2082 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.Enumeration;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.carbon.*;
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+class Safari extends WebBrowser {
+
+ /* Objective-C WebView delegate */
+ int delegate;
+
+ /* Carbon HIView handle */
+ int webViewHandle, webView;
+ int windowBoundsHandler;
+ int preferences;
+
+ boolean changingLocation, hasNewFocusElement;
+ String lastHoveredLinkURL, lastNavigateURL;
+ String html;
+ int identifier;
+ int resourceCount;
+ int lastMouseMoveX, lastMouseMoveY;
+ String url = ""; //$NON-NLS-1$
+ Point location;
+ Point size;
+ boolean statusBar = true, toolBar = true, ignoreDispose;
+ //TEMPORARY CODE
+// boolean doit;
+
+ static boolean Initialized;
+ static Callback Callback3, Callback7;
+
+ static final int MIN_SIZE = 16;
+ static final int MAX_PROGRESS = 100;
+ static final String WebElementLinkURLKey = "WebElementLinkURL"; //$NON-NLS-1$
+ static final String AGENT_STRING = "Safari/412.0"; /* Safari version on OSX 10.4 initial release */ //$NON-NLS-1$
+ static final String URI_FROMMEMORY = "file:///"; //$NON-NLS-1$
+ static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
+ static final String PROTOCOL_HTTP = "http://"; //$NON-NLS-1$
+ static final String URI_APPLEWEBDATA = "applewebdata://"; //$NON-NLS-1$
+ static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+ static final String HEADER_SETCOOKIE = "Set-Cookie"; //$NON-NLS-1$
+ static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$
+ static final String BROWSER_WINDOW = "org.eclipse.swt.browser.Browser.Window"; //$NON-NLS-1$
+ static final String SAFARI_EVENTS_FIX_KEY = "org.eclipse.swt.internal.safariEventsFix"; //$NON-NLS-1$
+
+ /* event strings */
+ static final String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
+ static final String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+ static final String DOMEVENT_FOCUSIN = "DOMFocusIn"; //$NON-NLS-1$
+ static final String DOMEVENT_FOCUSOUT = "DOMFocusOut"; //$NON-NLS-1$
+
+ static {
+ NativeClearSessions = new Runnable() {
+ public void run() {
+ int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage);
+ int cookies = Cocoa.objc_msgSend (storage, Cocoa.S_cookies);
+ int count = Cocoa.objc_msgSend (cookies, Cocoa.S_count);
+ for (int i = 0; i < count; i++) {
+ int cookie = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, i);
+ boolean isSession = Cocoa.objc_msgSend (cookie, Cocoa.S_isSessionOnly) != 0;
+ if (isSession) {
+ Cocoa.objc_msgSend (storage, Cocoa.S_deleteCookie, cookie);
+ }
+ }
+ }
+ };
+
+ NativeGetCookie = new Runnable () {
+ public void run () {
+ int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage);
+ int length = CookieUrl.length ();
+ char[] buffer = new char[length];
+ CookieUrl.getChars (0, length, buffer, 0);
+ int urlString = OS.CFStringCreateWithCharacters (0, buffer, length);
+ int url = Cocoa.objc_msgSend (Cocoa.C_NSURL, Cocoa.S_URLWithString, urlString);
+ OS.CFRelease (urlString);
+ int cookies = Cocoa.objc_msgSend (storage, Cocoa.S_cookiesForURL, url);
+ int count = Cocoa.objc_msgSend (cookies, Cocoa.S_count);
+ if (count == 0) return;
+
+ length = CookieName.length ();
+ buffer = new char[length];
+ CookieName.getChars (0, length, buffer, 0);
+ int name = OS.CFStringCreateWithCharacters (0, buffer, length);
+ for (int i = 0; i < count; i++) {
+ int current = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, i);
+ int currentName = Cocoa.objc_msgSend (current, Cocoa.S_name);
+ if (Cocoa.objc_msgSend (currentName, Cocoa.S_compare, name) == Cocoa.NSOrderedSame) {
+ int value = Cocoa.objc_msgSend (current, Cocoa.S_value);
+ length = OS.CFStringGetLength (value);
+ buffer = new char[length];
+ CFRange range = new CFRange ();
+ range.length = length;
+ OS.CFStringGetCharacters (value, range, buffer);
+ CookieValue = new String (buffer);
+ OS.CFRelease (name);
+ return;
+ }
+ }
+ OS.CFRelease (name);
+ }
+ };
+
+ NativeSetCookie = new Runnable () {
+ public void run () {
+ int length = CookieUrl.length ();
+ char[] buffer = new char[length];
+ CookieUrl.getChars (0, length, buffer, 0);
+ int urlString = OS.CFStringCreateWithCharacters (0, buffer, length);
+ int url = Cocoa.objc_msgSend (Cocoa.C_NSURL, Cocoa.S_URLWithString, urlString);
+ OS.CFRelease (urlString);
+
+ length = CookieValue.length ();
+ buffer = new char[length];
+ CookieValue.getChars (0, length, buffer, 0);
+ int value = OS.CFStringCreateWithCharacters (0, buffer, length);
+ length = HEADER_SETCOOKIE.length ();
+ buffer = new char[length];
+ HEADER_SETCOOKIE.getChars (0, length, buffer, 0);
+ int key = OS.CFStringCreateWithCharacters (0, buffer, length);
+ int headers = Cocoa.objc_msgSend (Cocoa.C_NSMutableDictionary, Cocoa.S_dictionaryWithCapacity, 1);
+ Cocoa.objc_msgSend (headers, Cocoa.S_setValue, value, key);
+ OS.CFRelease (key);
+ OS.CFRelease (value);
+
+ int cookies = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookie, Cocoa.S_cookiesWithResponseHeaderFields, headers, url);
+ if (Cocoa.objc_msgSend (cookies, Cocoa.S_count) == 0) return;
+ int cookie = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, 0);
+ int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage);
+ Cocoa.objc_msgSend (storage, Cocoa.S_setCookie, cookie);
+ CookieResult = true;
+ }
+ };
+ }
+
+public void create (Composite parent, int style) {
+ /*
+ * Note. Loading the webkit bundle on Jaguar causes a crash.
+ * The workaround is to detect any OS prior to 10.30 and fail
+ * without crashing.
+ */
+ if (OS.VERSION < 0x1030) {
+ browser.dispose();
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+
+ /*
+ * Bug in Safari on OSX 10.5 (Leopard) only. VoiceOver no longer follows focus when
+ * HIWebViewCreate is used to create a WebView. The VoiceOver cursor (activated by
+ * Control+Alt+arrows) continues to work, but keyboard focus is not tracked. The fix
+ * is to create the WebView with HICocoaViewCreate (api introduced in OSX 10.5) when
+ * running on OSX 10.5.
+ */
+ int outControl[] = new int[1];
+ if (OS.VERSION >= 0x1050) {
+ webView = Cocoa.objc_msgSend(Cocoa.objc_msgSend(Cocoa.C_WebView, Cocoa.S_alloc), Cocoa.S_initWithFrame_frameName_groupName, new NSRect(), 0, 0);
+ if (webView != 0) {
+ Cocoa.HICocoaViewCreate(webView, 0, outControl);
+ webViewHandle = outControl[0];
+ Cocoa.objc_msgSend(webView, Cocoa.S_release);
+ }
+ } else {
+ Cocoa.HIWebViewCreate(outControl);
+ webViewHandle = outControl[0];
+ if (webViewHandle != 0) {
+ webView = Cocoa.HIWebViewGetWebView(webViewHandle);
+ }
+ }
+ if (webViewHandle == 0) {
+ browser.dispose();
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+
+ Display display = browser.getDisplay();
+ display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), browser});
+
+ /*
+ * WebKit's DOM listener api became functional in OSX 10.4. If OSX 10.4 or
+ * later is detected then override the default event mechanism to not send key
+ * events and some mouse events so that the browser can send them by listening
+ * to the DOM instead.
+ */
+ if (!(OS.VERSION < 0x1040)) {
+ browser.setData(SAFARI_EVENTS_FIX_KEY);
+ }
+
+ /*
+ * Bug in Safari. For some reason, every application must contain
+ * a visible window that has never had a WebView or mouse move events
+ * are not delivered. This seems to happen after a browser has been
+ * either hidden or disposed in any window. The fix is to create a
+ * single transparent overlay window that is disposed when the display
+ * is disposed.
+ */
+ if (display.getData(BROWSER_WINDOW) == null) {
+ Rect bounds = new Rect ();
+ OS.SetRect (bounds, (short) 0, (short) 0, (short) 1, (short) 1);
+ final int[] outWindow = new int[1];
+ OS.CreateNewWindow(OS.kOverlayWindowClass, 0, bounds, outWindow);
+ OS.ShowWindow(outWindow[0]);
+ OS.HIObjectSetAccessibilityIgnored (outWindow[0], true);
+ display.disposeExec(new Runnable() {
+ public void run() {
+ if (outWindow[0] != 0) {
+ OS.DisposeWindow(outWindow[0]);
+ }
+ outWindow[0] = 0;
+ }
+ });
+ display.setData(BROWSER_WINDOW, outWindow);
+ }
+
+ /*
+ * Bug in Safari. The WebView does not draw properly if it is embedded as
+ * sub view of the browser handle. The fix is to add the web view to the
+ * window root control and resize it on top of the browser handle.
+ *
+ * Note that when the browser is reparented, the web view has to
+ * be reparented by hand by hooking kEventControlOwningWindowChanged.
+ */
+ int window = OS.GetControlOwner(browser.handle);
+ int[] contentView = new int[1];
+ OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView);
+ OS.HIViewAddSubview(contentView[0], webViewHandle);
+ OS.HIViewChangeFeatures(webViewHandle, OS.kHIViewFeatureIsOpaque, 0);
+
+ /*
+ * Bug in Safari. The WebView does not receive mouse and key events when it is added
+ * to a visible top window. It is assumed that Safari hooks its own event listener
+ * when the top window emits the kEventWindowShown event. The workaround is to send a
+ * fake kEventWindowShown event to the top window after the WebView has been added
+ * to the HIView (after the top window is visible) to give Safari a chance to hook
+ * events.
+ */
+ OS.HIViewSetVisible(webViewHandle, true);
+ if (browser.getShell().isVisible()) {
+ int[] showEvent = new int[1];
+ OS.CreateEvent(0, OS.kEventClassWindow, OS.kEventWindowShown, 0.0, OS.kEventAttributeUserEvent, showEvent);
+ OS.SetEventParameter(showEvent[0], OS.kEventParamDirectObject, OS.typeWindowRef, 4, new int[] {OS.GetControlOwner(browser.handle)});
+ OS.SendEventToEventTarget(showEvent[0], OS.GetWindowEventTarget(window));
+ if (showEvent[0] != 0) OS.ReleaseEvent(showEvent[0]);
+ }
+
+ /*
+ * This code is intentionally commented. Setting a group name is the right thing
+ * to do in order to avoid multiple open window requests. For some reason, Safari
+ * crashes when requested to reopen the same window if that window was previously
+ * closed. This may be because that window was not correctly closed.
+ */
+// String groupName = "MyDocument"; //$NON-NLS-1$
+// int length = groupName.length();
+// char[] buffer = new char[length];
+// groupName.getChars(0, length, buffer, 0);
+// int groupNameString = OS.CFStringCreateWithCharacters(0, buffer, length);
+// // [webView setGroupName:@"MyDocument"];
+// WebKit.objc_msgSend(webView, WebKit.S_setGroupName, groupNameString);
+// OS.CFRelease(groupNameString);
+
+ final int notificationCenter = Cocoa.objc_msgSend(Cocoa.C_NSNotificationCenter, Cocoa.S_defaultCenter);
+
+ Listener listener = new Listener() {
+ public void handleEvent(Event e) {
+ switch (e.type) {
+ case SWT.Dispose: {
+ /* make this handler run after other dispose listeners */
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (e.type, e);
+ e.type = SWT.NONE;
+
+ OS.RemoveEventHandler(windowBoundsHandler);
+ windowBoundsHandler = 0;
+
+ e.display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), null});
+
+ Cocoa.objc_msgSend(webView, Cocoa.S_setFrameLoadDelegate, 0);
+ Cocoa.objc_msgSend(webView, Cocoa.S_setResourceLoadDelegate, 0);
+ Cocoa.objc_msgSend(webView, Cocoa.S_setUIDelegate, 0);
+ Cocoa.objc_msgSend(webView, Cocoa.S_setPolicyDelegate, 0);
+ Cocoa.objc_msgSend(webView, Cocoa.S_setDownloadDelegate, 0);
+ Cocoa.objc_msgSend(notificationCenter, Cocoa.S_removeObserver, delegate);
+
+ Cocoa.objc_msgSend(delegate, Cocoa.S_release);
+ OS.DisposeControl(webViewHandle);
+ webView = webViewHandle = 0;
+ html = null;
+ lastHoveredLinkURL = lastNavigateURL = null;
+
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ ((BrowserFunction)elements.nextElement ()).dispose (false);
+ }
+ functions = null;
+
+ if (preferences != 0) {
+ Cocoa.objc_msgSend (preferences, Cocoa.S_release);
+ }
+ preferences = 0;
+ break;
+ }
+ case SWT.FocusIn: {
+ hasNewFocusElement = true;
+ OS.SetKeyboardFocus(OS.GetControlOwner(browser.handle), webViewHandle, (short)-1);
+ break;
+ }
+ }
+ }
+ };
+ browser.addListener(SWT.Dispose, listener);
+ browser.addListener(SWT.FocusIn, listener);
+ browser.addListener(SWT.KeyDown, listener); /* needed to make browser traversable */
+
+ if (Callback3 == null) Callback3 = new Callback(this.getClass(), "eventProc3", 3); //$NON-NLS-1$
+ int callback3Address = Callback3.getAddress();
+ if (callback3Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+
+ int[] mask = new int[] {
+ OS.kEventClassKeyboard, OS.kEventRawKeyDown,
+ OS.kEventClassControl, OS.kEventControlDraw,
+ OS.kEventClassControl, OS.kEventControlGetClickActivation,
+ OS.kEventClassControl, OS.kEventControlSetCursor,
+ OS.kEventClassTextInput, OS.kEventTextInputUnicodeForKeyEvent,
+ };
+ OS.InstallEventHandler(OS.GetControlEventTarget(webViewHandle), callback3Address, mask.length / 2, mask, webViewHandle, null);
+ int[] mask1 = new int[] {
+ OS.kEventClassControl, OS.kEventControlBoundsChanged,
+ OS.kEventClassControl, OS.kEventControlVisibilityChanged,
+ OS.kEventClassControl, OS.kEventControlOwningWindowChanged,
+ };
+ OS.InstallEventHandler(OS.GetControlEventTarget(browser.handle), callback3Address, mask1.length / 2, mask1, browser.handle, null);
+ int[] mask2 = new int[] {
+ OS.kEventClassWindow, OS.kEventWindowBoundsChanged,
+ };
+ int[] outRef = new int[1];
+ OS.InstallEventHandler(OS.GetWindowEventTarget(window), callback3Address, mask2.length / 2, mask2, browser.handle, outRef);
+ windowBoundsHandler = outRef[0];
+
+ if (Callback7 == null) Callback7 = new Callback(this.getClass(), "eventProc7", 7); //$NON-NLS-1$
+ int callback7Address = Callback7.getAddress();
+ if (callback7Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+
+ // delegate = [[WebResourceLoadDelegate alloc] init eventProc];
+ delegate = Cocoa.objc_msgSend(Cocoa.C_WebKitDelegate, Cocoa.S_alloc);
+ delegate = Cocoa.objc_msgSend(delegate, Cocoa.S_initWithProc, callback7Address, webViewHandle);
+
+ // [webView setFrameLoadDelegate:delegate];
+ Cocoa.objc_msgSend(webView, Cocoa.S_setFrameLoadDelegate, delegate);
+
+ // [webView setResourceLoadDelegate:delegate];
+ Cocoa.objc_msgSend(webView, Cocoa.S_setResourceLoadDelegate, delegate);
+
+ // [webView setUIDelegate:delegate];
+ Cocoa.objc_msgSend(webView, Cocoa.S_setUIDelegate, delegate);
+
+ /* register delegate for all notifications sent out from webview */
+ Cocoa.objc_msgSend(notificationCenter, Cocoa.S_addObserver_selector_name_object, delegate, Cocoa.S_handleNotification, 0, webView);
+
+ // [webView setPolicyDelegate:delegate];
+ Cocoa.objc_msgSend(webView, Cocoa.S_setPolicyDelegate, delegate);
+
+ // [webView setDownloadDelegate:delegate];
+ Cocoa.objc_msgSend(webView, Cocoa.S_setDownloadDelegate, delegate);
+
+ // [webView setApplicationNameForUserAgent:applicationName];
+ int length = AGENT_STRING.length();
+ char[] chars = new char[length];
+ AGENT_STRING.getChars(0, length, chars, 0);
+ int sHandle = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(webView, Cocoa.S_setApplicationNameForUserAgent, sHandle);
+ OS.CFRelease(sHandle);
+
+ if (OS.VERSION < 0x1050 && display.getActiveShell() == browser.getShell()) {
+ Cocoa.objc_msgSend(Cocoa.objc_msgSend(webView, Cocoa.S_window), Cocoa.S_makeKeyWindow);
+ }
+
+ if (!Initialized) {
+ Initialized = true;
+ /* disable applets */
+ int preferences = Cocoa.objc_msgSend(Cocoa.C_WebPreferences, Cocoa.S_standardPreferences);
+ Cocoa.objc_msgSend(preferences, Cocoa.S_setJavaEnabled, 0);
+ }
+}
+
+static int eventProc3(int nextHandler, int theEvent, int userData) {
+ Widget widget = Display.getCurrent().findWidget(userData);
+ if (widget instanceof Browser) {
+ return ((Safari)((Browser)widget).webBrowser).handleCallback(nextHandler, theEvent);
+ }
+ return OS.eventNotHandledErr;
+}
+
+static int eventProc7(int webview, int userData, int selector, int arg0, int arg1, int arg2, int arg3) {
+ Widget widget = Display.getCurrent().findWidget(userData);
+ if (widget instanceof Browser) {
+ return ((Safari)((Browser)widget).webBrowser).handleCallback(selector, arg0, arg1, arg2, arg3);
+ }
+ return 0;
+}
+
+static String getString (int ptr) {
+ int length = OS.CFStringGetLength (ptr);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange ();
+ range.length = length;
+ OS.CFStringGetCharacters (ptr, range, buffer);
+ return new String (buffer);
+}
+
+public boolean back() {
+ html = null;
+ return Cocoa.objc_msgSend(webView, Cocoa.S_goBack) != 0;
+}
+
+public boolean execute(String script) {
+ int length = script.length();
+ char[] buffer = new char[length];
+ script.getChars(0, length, buffer, 0);
+ int string = OS.CFStringCreateWithCharacters(0, buffer, length);
+
+ int value = Cocoa.objc_msgSend(webView, Cocoa.S_stringByEvaluatingJavaScriptFromString, string);
+ OS.CFRelease(string);
+ return value != 0;
+}
+
+public boolean forward() {
+ html = null;
+ return Cocoa.objc_msgSend(webView, Cocoa.S_goForward) != 0;
+}
+
+public String getBrowserType () {
+ return "safari"; //$NON-NLS-1$
+}
+
+public String getText() {
+ int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+ int dataSource = Cocoa.objc_msgSend(mainFrame, Cocoa.S_dataSource);
+ if (dataSource == 0) return ""; //$NON-NLS-1$
+ int representation = Cocoa.objc_msgSend(dataSource, Cocoa.S_representation);
+ if (representation == 0) return ""; //$NON-NLS-1$
+ int source = Cocoa.objc_msgSend(representation, Cocoa.S_documentSource);
+ if (source == 0) return ""; //$NON-NLS-1$
+ int length = OS.CFStringGetLength(source);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(source, range, buffer);
+ return new String(buffer);
+}
+
+public String getUrl() {
+ return url;
+}
+
+int handleCallback(int nextHandler, int theEvent) {
+ int eventKind = OS.GetEventKind(theEvent);
+ switch (OS.GetEventClass(theEvent)) {
+ case OS.kEventClassControl:
+ switch (eventKind) {
+ case OS.kEventControlGetClickActivation: {
+ OS.SetEventParameter (theEvent, OS.kEventParamClickActivation, OS.typeClickActivationResult, 4, new int [] {OS.kActivateAndHandleClick});
+ return OS.noErr;
+ }
+ case OS.kEventControlSetCursor: {
+ return OS.noErr;
+ }
+ case OS.kEventControlDraw: {
+ /*
+ * Bug on Safari. The web view cannot be obscured by other views above it.
+ * This problem is specified in the apple documentation for HiWebViewCreate.
+ * The workaround is to don't draw the web view when it is not visible.
+ */
+ if (!browser.isVisible ()) return OS.noErr;
+ break;
+ }
+ case OS.kEventControlOwningWindowChanged: {
+ /* Reparent the web view handler */
+ int window = OS.GetControlOwner(browser.handle);
+ int[] contentView = new int[1];
+ OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView);
+ OS.HIViewAddSubview(contentView[0], webViewHandle);
+
+ /* Reset the kEventWindowBoundsChanged handler */
+ OS.RemoveEventHandler(windowBoundsHandler);
+ int[] mask2 = new int[] {
+ OS.kEventClassWindow, OS.kEventWindowBoundsChanged,
+ };
+ int[] outRef = new int[1];
+ OS.InstallEventHandler(OS.GetWindowEventTarget(window), Callback3.getAddress(), mask2.length / 2, mask2, browser.handle, outRef);
+ windowBoundsHandler = outRef[0];
+ break;
+ }
+ case OS.kEventControlBoundsChanged:
+ case OS.kEventControlVisibilityChanged: {
+ /*
+ * Bug on Safari. The web view cannot be obscured by other views above it.
+ * This problem is specified in the apple documentation for HiWebViewCreate.
+ * The workaround is to hook kEventControlVisibilityChanged on the browser
+ * and move the browser out of the screen when hidden and restore its bounds
+ * when shown.
+ */
+ CGRect bounds = new CGRect();
+ if (!browser.isVisible()) {
+ bounds.x = bounds.y = -MIN_SIZE;
+ bounds.width = bounds.height = MIN_SIZE;
+ OS.HIViewSetFrame(webViewHandle, bounds);
+ } else {
+ OS.HIViewGetBounds(browser.handle, bounds);
+ int[] contentView = new int[1];
+ OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(browser.handle)), OS.kHIViewWindowContentID(), contentView);
+ OS.HIViewConvertRect(bounds, browser.handle, contentView[0]);
+ /*
+ * Bug in Safari. For some reason, the web view will display incorrectly or
+ * blank depending on its contents, if its size is set to a value smaller than
+ * MIN_SIZE. It will not display properly even after the size is made larger.
+ * The fix is to avoid setting sizes smaller than MIN_SIZE.
+ */
+ if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE;
+ if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE;
+ OS.HIViewSetFrame(webViewHandle, bounds);
+ }
+ break;
+ }
+ }
+ case OS.kEventClassWindow:
+ switch (eventKind) {
+ case OS.kEventWindowBoundsChanged:
+ /*
+ * Bug on Safari. Resizing the height of a Shell containing a Browser at
+ * a fixed location causes the Browser to redraw at a wrong location.
+ * The web view is a HIView container that internally hosts
+ * a Cocoa NSView that uses a coordinates system with the origin at the
+ * bottom left corner of a window instead of the coordinates system used
+ * in Carbon that starts at the top left corner. The workaround is to
+ * reposition the web view every time the Shell of the Browser is resized.
+ *
+ * Note the size should not be updated if the browser is hidden.
+ */
+ if (browser.isVisible()) {
+ CGRect oldBounds = new CGRect();
+ OS.GetEventParameter (theEvent, OS.kEventParamOriginalBounds, OS.typeHIRect, null, CGRect.sizeof, null, oldBounds);
+ CGRect bounds = new CGRect();
+ OS.GetEventParameter (theEvent, OS.kEventParamCurrentBounds, OS.typeHIRect, null, CGRect.sizeof, null, bounds);
+ if (oldBounds.height == bounds.height) break;
+ OS.HIViewGetBounds(browser.handle, bounds);
+ int[] contentView = new int[1];
+ OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(browser.handle)), OS.kHIViewWindowContentID(), contentView);
+ OS.HIViewConvertRect(bounds, browser.handle, contentView[0]);
+ /*
+ * Bug in Safari. For some reason, the web view will display incorrectly or
+ * blank depending on its contents, if its size is set to a value smaller than
+ * MIN_SIZE. It will not display properly even after the size is made larger.
+ * The fix is to avoid setting sizes smaller than MIN_SIZE.
+ */
+ if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE;
+ if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE;
+ bounds.x++;
+ /* Note that the bounds needs to change */
+ OS.HIViewSetFrame(webViewHandle, bounds);
+ bounds.x--;
+ OS.HIViewSetFrame(webViewHandle, bounds);
+ }
+ }
+ case OS.kEventClassKeyboard:
+ switch (eventKind) {
+ case OS.kEventRawKeyDown: {
+ /*
+ * Bug in Safari. The WebView blocks the propagation of certain Carbon events
+ * such as kEventRawKeyDown. On the Mac, Carbon events propagate from the
+ * Focus Target Handler to the Control Target Handler, Window Target and finally
+ * the Application Target Handler. It is assumed that WebView hooks its events
+ * on the Window Target and does not pass kEventRawKeyDown to the next handler.
+ * Since kEventRawKeyDown events never make it to the Application Target Handler,
+ * the Application Target Handler never gets to emit kEventTextInputUnicodeForKeyEvent
+ * used by SWT to send a SWT.KeyDown event.
+ * The workaround is to hook kEventRawKeyDown on the Control Target Handler which gets
+ * called before the WebView hook on the Window Target Handler. Then, forward this event
+ * directly to the Application Target Handler. Note that if in certain conditions Safari
+ * does not block the kEventRawKeyDown, then multiple kEventTextInputUnicodeForKeyEvent
+ * events might be generated as a result of this workaround.
+ */
+ //TEMPORARY CODE
+// doit = false;
+// OS.SendEventToEventTarget(theEvent, OS.GetApplicationEventTarget());
+// if (!doit) return OS.noErr;
+
+ int[] length = new int[1];
+ int status = OS.GetEventParameter (theEvent, OS.kEventParamKeyUnicodes, OS.typeUnicodeText, null, 4, length, (char[])null);
+ if (status == OS.noErr && length[0] != 0) {
+ int[] modifiers = new int[1];
+ OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, 4, null, modifiers);
+ char[] chars = new char[1];
+ OS.GetEventParameter (theEvent, OS.kEventParamKeyUnicodes, OS.typeUnicodeText, null, 2, null, chars);
+ if ((modifiers[0] & OS.cmdKey) != 0) {
+ switch (chars[0]) {
+ case 'v': {
+ Cocoa.objc_msgSend (webView, Cocoa.S_paste);
+ return OS.noErr;
+ }
+ case 'c': {
+ Cocoa.objc_msgSend (webView, Cocoa.S_copy);
+ return OS.noErr;
+ }
+ case 'x': {
+ Cocoa.objc_msgSend (webView, Cocoa.S_cut);
+ return OS.noErr;
+ }
+ }
+ }
+ }
+ /*
+ * 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 and its
+ * ancestor while the DOM listener is handling the event, in case the
+ * Browser gets disposed in a callback.
+ */
+ int handle = webViewHandle, root = OS.HIViewGetSuperview (webViewHandle);
+ OS.CFRetain (handle);
+ OS.CFRetain (root);
+ int result = OS.CallNextEventHandler (nextHandler, theEvent);
+ OS.CFRelease (handle);
+ OS.CFRelease (root);
+ return result;
+ }
+ }
+ case OS.kEventClassTextInput:
+ switch (eventKind) {
+ case OS.kEventTextInputUnicodeForKeyEvent: {
+ /*
+ * Note. This event is received from the Window Target therefore after it was received
+ * by the Focus Target. The SWT.KeyDown event is sent by SWT on the Focus Target. If it
+ * is received here, then the SWT.KeyDown doit flag must have been left to the value
+ * true. For package visibility reasons we cannot access the doit flag directly.
+ *
+ * Sequence of events when the user presses a key down
+ *
+ * .Control Target - kEventRawKeyDown
+ * .forward to ApplicationEventTarget
+ * .Focus Target kEventTextInputUnicodeForKeyEvent - SWT emits SWT.KeyDown -
+ * blocks further propagation if doit false. Browser does not know directly about
+ * the doit flag value.
+ * .Window Target kEventTextInputUnicodeForKeyEvent - if received, Browser knows
+ * SWT.KeyDown is not blocked and event should be sent to WebKit
+ * Return from Control Target - kEventRawKeyDown: let the event go to WebKit if doit true
+ * (eventNotHandledErr) or stop it (noErr).
+ */
+ //TEMPORARY CODE
+// doit = true;
+ break;
+ }
+ }
+ }
+ return OS.eventNotHandledErr;
+}
+
+/* Here we dispatch all WebView upcalls. */
+int handleCallback(int selector, int arg0, int arg1, int arg2, int arg3) {
+ int ret = 0;
+ // for meaning of selector see WebKitDelegate methods in webkit.c
+ switch (selector) {
+ case 1: didFailProvisionalLoadWithError(arg0, arg1); break;
+ case 2: didFinishLoadForFrame(arg0); break;
+ case 3: didReceiveTitle(arg0, arg1); break;
+ case 4: didStartProvisionalLoadForFrame(arg0); break;
+ case 5: didFinishLoadingFromDataSource(arg0, arg1); break;
+ case 6: didFailLoadingWithError(arg0, arg1, arg2); break;
+ case 7: ret = identifierForInitialRequest(arg0, arg1); break;
+ case 8: ret = willSendRequest(arg0, arg1, arg2, arg3); break;
+ case 9: handleNotification(arg0); break;
+ case 10: didCommitLoadForFrame(arg0); break;
+ case 11: ret = createWebViewWithRequest(arg0); break;
+ case 12: webViewShow(arg0); break;
+ case 13: setFrame(arg0); break;
+ case 14: webViewClose(); break;
+ case 15: ret = contextMenuItemsForElement(arg0, arg1); break;
+ case 16: setStatusBarVisible(arg0); break;
+ case 17: setResizable(arg0); break;
+ case 18: setToolbarsVisible(arg0); break;
+ case 19: decidePolicyForMIMEType(arg0, arg1, arg2, arg3); break;
+ case 20: decidePolicyForNavigationAction(arg0, arg1, arg2, arg3); break;
+ case 21: decidePolicyForNewWindowAction(arg0, arg1, arg2, arg3); break;
+ case 22: unableToImplementPolicyWithError(arg0, arg1); break;
+ case 23: setStatusText(arg0); break;
+ case 24: webViewFocus(); break;
+ case 25: webViewUnfocus(); break;
+ case 26: runJavaScriptAlertPanelWithMessage(arg0); break;
+ case 27: ret = runJavaScriptConfirmPanelWithMessage(arg0); break;
+ case 28: runOpenPanelForFileButtonWithResultListener(arg0); break;
+ case 29: decideDestinationWithSuggestedFilename(arg0, arg1); break;
+ case 30: mouseDidMoveOverElement(arg0, arg1); break;
+ case 31: didChangeLocationWithinPageForFrame(arg0); break;
+ case 32: handleEvent(arg0); break;
+ case 33: windowScriptObjectAvailable(arg0); break;
+ case 34: ret = callJava(arg0, arg1, arg2); break;
+ case 35: didReceiveAuthenticationChallengefromDataSource(arg0, arg1, arg2); break;
+ }
+ return ret;
+}
+
+public boolean isBackEnabled() {
+ return Cocoa.objc_msgSend(webView, Cocoa.S_canGoBack) != 0;
+}
+
+public boolean isForwardEnabled() {
+ return Cocoa.objc_msgSend(webView, Cocoa.S_canGoForward) != 0;
+}
+
+public void refresh() {
+ Cocoa.objc_msgSend(webView, Cocoa.S_reload, 0);
+}
+
+public boolean setText(String html) {
+ /*
+ * Bug in Safari. The web view segment faults in some circumstances
+ * when the text changes during the location changing callback. The
+ * fix is to defer the work until the callback is done.
+ */
+ if (changingLocation) {
+ this.html = html;
+ } else {
+ _setText(html);
+ }
+ return true;
+}
+
+void _setText(String html) {
+ int length = html.length();
+ char[] buffer = new char[length];
+ html.getChars(0, length, buffer, 0);
+ int string = OS.CFStringCreateWithCharacters(0, buffer, length);
+
+ length = URI_FROMMEMORY.length();
+ buffer = new char[length];
+ URI_FROMMEMORY.getChars(0, length, buffer, 0);
+ int URLString = OS.CFStringCreateWithCharacters(0, buffer, length);
+
+ /*
+ * Note. URLWithString uses autorelease. The resulting URL
+ * does not need to be released.
+ * URL = [NSURL URLWithString:(NSString *)URLString]
+ */
+ int URL = Cocoa.objc_msgSend(Cocoa.C_NSURL, Cocoa.S_URLWithString, URLString);
+ OS.CFRelease(URLString);
+
+ //mainFrame = [webView mainFrame];
+ int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+
+ //[mainFrame loadHTMLString:(NSString *) string baseURL:(NSURL *)URL];
+ Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadHTMLStringbaseURL, string, URL);
+ OS.CFRelease(string);
+}
+
+public boolean setUrl(String url) {
+ html = null;
+
+ if (url.indexOf('/') == 0) {
+ url = PROTOCOL_FILE + url;
+ } else if (url.indexOf(':') == -1) {
+ url = PROTOCOL_HTTP + url;
+ }
+
+ int inURL = 0;
+ char[] chars = new char[url.length()];
+ url.getChars(0, chars.length, chars, 0);
+ int str = OS.CFStringCreateWithCharacters(0, chars, chars.length);
+ if (str != 0) {
+ char[] unescapedChars = new char[] {'%', '#'};
+ int unescapedStr = OS.CFStringCreateWithCharacters(0, unescapedChars, unescapedChars.length);
+ int escapedStr = OS.CFURLCreateStringByAddingPercentEscapes(OS.kCFAllocatorDefault, str, unescapedStr, 0, OS.kCFStringEncodingUTF8);
+ if (escapedStr != 0) {
+ inURL = OS.CFURLCreateWithString(OS.kCFAllocatorDefault, escapedStr, 0);
+ OS.CFRelease(escapedStr);
+ }
+ if (unescapedStr != 0) OS.CFRelease(unescapedStr);
+ OS.CFRelease(str);
+ }
+ if (inURL == 0) return false;
+
+ //request = [NSURLRequest requestWithURL:(NSURL*)inURL];
+ int request = Cocoa.objc_msgSend(Cocoa.C_NSURLRequest, Cocoa.S_requestWithURL, inURL);
+ OS.CFRelease(inURL);
+
+ //mainFrame = [webView mainFrame];
+ int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+
+ //[mainFrame loadRequest:request];
+ Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadRequest, request);
+
+ return true;
+}
+
+public void stop() {
+ html = null;
+ Cocoa.objc_msgSend(webView, Cocoa.S_stopLoading, 0);
+}
+
+/* WebFrameLoadDelegate */
+void didChangeLocationWithinPageForFrame(int frame) {
+ //id url= [[[[frame provisionalDataSource] request] URL] absoluteString];
+ int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource);
+ int request = Cocoa.objc_msgSend(dataSource, Cocoa.S_request);
+ int url = Cocoa.objc_msgSend(request, Cocoa.S_URL);
+ int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString);
+ int length = OS.CFStringGetLength(s);
+ if (length == 0) return;
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(s, range, buffer);
+ String url2 = new String(buffer);
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ final Display display = browser.getDisplay();
+ boolean top = frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+ if (top) {
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = display;
+ statusText.widget = browser;
+ statusText.text = url2;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ }
+ LocationEvent location = new LocationEvent(browser);
+ location.display = display;
+ location.widget = browser;
+ location.location = url2;
+ location.top = top;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changed(location);
+ }
+}
+
+void didFailProvisionalLoadWithError(int error, int frame) {
+ if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. However, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ identifier = 0;
+ }
+}
+
+void didFinishLoadForFrame(int frame) {
+ hookDOMFocusListeners(frame);
+ hookDOMMouseListeners(frame);
+ if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) {
+ hookDOMKeyListeners(frame);
+
+ final Display display = browser.getDisplay();
+ /*
+ * To be consistent with other platforms a title event should be fired when a
+ * page has completed loading. A page with a <title> tag will do this
+ * automatically when the didReceiveTitle callback is received. However a page
+ * without a <title> tag will not do this by default, so fire the event
+ * here with the page's url as the title.
+ */
+ int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource);
+ if (dataSource != 0) {
+ int title = Cocoa.objc_msgSend(dataSource, Cocoa.S_pageTitle);
+ if (title == 0) { /* page has no title */
+ final TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = display;
+ newEvent.widget = browser;
+ newEvent.title = url;
+ for (int i = 0; i < titleListeners.length; i++) {
+ final TitleListener listener = titleListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The workaround is to invoke Display.asyncExec()
+ * so that the Browser does not crash if this is attempted.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed()) {
+ listener.changed(newEvent);
+ }
+ }
+ }
+ );
+ }
+ }
+ }
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = MAX_PROGRESS;
+ progress.total = MAX_PROGRESS;
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The ProgressBar widget currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncExec() so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed()) {
+ listener.completed(progress);
+ }
+ }
+ }
+ );
+ }
+
+ /* re-install registered functions */
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ BrowserFunction function = (BrowserFunction)elements.nextElement ();
+ execute (function.functionString);
+ }
+
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. Howeever, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ identifier = 0;
+ }
+}
+
+void hookDOMFocusListeners(int frame) {
+ /*
+ * These listeners only need to be hooked for OSX 10.4 (Tiger). The WebKit on
+ * OSX < 10.4 does not send these DOM events, and tab traversals that exit
+ * Safari are handled as of OSX 10.5 as a result of using HICocoaViewCreate,
+ * which makes these listeners unnecessary.
+ */
+ if (!(0x1040 <= OS.VERSION && OS.VERSION < 0x1050)) return;
+
+ int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument);
+ if (document == 0) return;
+
+ String string = DOMEVENT_FOCUSIN;
+ int length = string.length();
+ char[] chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ int ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+
+ string = DOMEVENT_FOCUSOUT;
+ length = string.length();
+ chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+}
+
+void hookDOMKeyListeners(int frame) {
+ /*
+ * WebKit's DOM listener api became functional in OSX 10.4, so if an earlier
+ * version than this is detected then do not hook the DOM listeners.
+ */
+ if (OS.VERSION < 0x1040) return;
+
+ int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument);
+ if (document == 0) return;
+
+ String string = DOMEVENT_KEYDOWN;
+ int length = string.length();
+ char[] chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ int ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+
+ string = DOMEVENT_KEYUP;
+ length = string.length();
+ chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+}
+
+void hookDOMMouseListeners(int frame) {
+ /*
+ * WebKit's DOM listener api became functional in OSX 10.4, so if an earlier
+ * version than this is detected then do not hook the DOM listeners.
+ */
+ if (OS.VERSION < 0x1040) return;
+
+ int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument);
+ if (document == 0) return;
+
+ String string = DOMEVENT_MOUSEDOWN;
+ int length = string.length();
+ char[] chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ int ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+
+ string = DOMEVENT_MOUSEUP;
+ length = string.length();
+ chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+
+ string = DOMEVENT_MOUSEMOVE;
+ length = string.length();
+ chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+
+ string = DOMEVENT_MOUSEWHEEL;
+ length = string.length();
+ chars = new char[length];
+ string.getChars(0, length, chars, 0);
+ ptr = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0);
+ OS.CFRelease(ptr);
+}
+
+void didReceiveTitle(int title, int frame) {
+ if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) {
+ int length = OS.CFStringGetLength(title);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(title, range, buffer);
+ String newTitle = new String(buffer);
+ TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.title = newTitle;
+ for (int i = 0; i < titleListeners.length; i++) {
+ titleListeners[i].changed(newEvent);
+ }
+ }
+}
+
+void didStartProvisionalLoadForFrame(int frame) {
+ /*
+ * This code is intentionally commented. WebFrameLoadDelegate:didStartProvisionalLoadForFrame is
+ * called before WebResourceLoadDelegate:willSendRequest and
+ * WebFrameLoadDelegate:didCommitLoadForFrame. The resource count is reset when didCommitLoadForFrame
+ * is received for the top frame.
+ */
+// int webView = WebKit.HIWebViewGetWebView(webViewHandle);
+// if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) {
+// /* reset resource status variables */
+// resourceCount= 0;
+// }
+}
+
+void didCommitLoadForFrame(int frame) {
+ //id url= [[[[frame provisionalDataSource] request] URL] absoluteString];
+ int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource);
+ int request = Cocoa.objc_msgSend(dataSource, Cocoa.S_request);
+ int url = Cocoa.objc_msgSend(request, Cocoa.S_URL);
+ int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString);
+ int length = OS.CFStringGetLength(s);
+ if (length == 0) return;
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(s, range, buffer);
+ String url2 = new String(buffer);
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ final Display display = browser.getDisplay();
+ boolean top = frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+ if (top) {
+ /* reset resource status variables */
+ resourceCount = 0;
+ this.url = url2;
+
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = 1;
+ progress.total = MAX_PROGRESS;
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The widget ProgressBar currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncexec so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed())
+ listener.changed(progress);
+ }
+ }
+ );
+ }
+
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = display;
+ statusText.widget = browser;
+ statusText.text = url2;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ }
+ LocationEvent location = new LocationEvent(browser);
+ location.display = display;
+ location.widget = browser;
+ location.location = url2;
+ location.top = top;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changed(location);
+ }
+}
+
+void windowScriptObjectAvailable (int windowScriptObject) {
+ String objectName = "external"; //$NON-NLS-1$
+ char[] chars = new char[objectName.length ()];
+ objectName.getChars (0, chars.length, chars, 0);
+ int str = OS.CFStringCreateWithCharacters (0, chars, chars.length);
+ if (str != 0) {
+ Cocoa.objc_msgSend (windowScriptObject, Cocoa.S_setValue, delegate, str);
+ OS.CFRelease (str);
+ }
+}
+
+/* WebResourceLoadDelegate */
+
+void didFinishLoadingFromDataSource(int identifier, int dataSource) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. Howeever, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ // this code is intentionally commented
+ //if (this.identifier == identifier) this.identifier = 0;
+}
+
+void didFailLoadingWithError(int identifier, int error, int dataSource) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. Howeever, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ // this code is intentionally commented
+ //if (this.identifier == identifier) this.identifier = 0;
+}
+
+void didReceiveAuthenticationChallengefromDataSource (int identifier, int challenge, int dataSource) {
+ /*
+ * Do not invoke the listeners if this challenge has been failed too many
+ * times because a listener is likely giving incorrect credentials repeatedly
+ * and will do so indefinitely.
+ */
+ int count = Cocoa.objc_msgSend (challenge, Cocoa.S_previousFailureCount);
+ if (count < 3) {
+ for (int i = 0; i < authenticationListeners.length; i++) {
+ AuthenticationEvent event = new AuthenticationEvent (browser);
+ event.location = lastNavigateURL;
+ authenticationListeners[i].authenticate (event);
+ if (!event.doit) {
+ int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender);
+ Cocoa.objc_msgSend (challengeSender, Cocoa.S_cancelAuthenticationChallenge, challenge);
+ return;
+ }
+ if (event.user != null && event.password != null) {
+ int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender);
+ int length = event.user.length ();
+ char[] buffer = new char[length];
+ event.user.getChars (0, length, buffer, 0);
+ int user = OS.CFStringCreateWithCharacters (0, buffer, length);
+ length = event.password.length ();
+ buffer = new char[length];
+ event.password.getChars (0, length, buffer, 0);
+ int password = OS.CFStringCreateWithCharacters (0, buffer, length);
+ int credential = Cocoa.objc_msgSend (Cocoa.C_NSURLCredential, Cocoa.S_credentialWithUser, user, password, Cocoa.NSURLCredentialPersistenceForSession);
+ Cocoa.objc_msgSend (challengeSender, Cocoa.S_useCredential, credential, challenge);
+ OS.CFRelease (password);
+ OS.CFRelease (user);
+ return;
+ }
+ }
+ }
+
+ /* no listener handled the challenge, so try to invoke the native panel */
+ int cls = Cocoa.C_WebPanelAuthenticationHandler;
+ if (cls != 0) {
+ int method = Cocoa.class_getClassMethod (cls, Cocoa.S_sharedHandler);
+ if (method != 0) {
+ int handler = Cocoa.objc_msgSend (cls, Cocoa.S_sharedHandler);
+ if (handler != 0) {
+ int window = Cocoa.objc_msgSend (webView, Cocoa.S_window);
+ Cocoa.objc_msgSend (handler, Cocoa.S_startAuthentication, challenge, window);
+ return;
+ }
+ }
+ }
+
+ /* the native panel was not available, so show a custom dialog */
+ String[] userReturn = new String[1], passwordReturn = new String[1];
+ int proposedCredential = Cocoa.objc_msgSend (challenge, Cocoa.S_proposedCredential);
+ if (proposedCredential != 0) {
+ int user = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_user);
+ userReturn[0] = getString (user);
+ boolean hasPassword = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_hasPassword) != 0;
+ if (hasPassword) {
+ int password = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_password);
+ passwordReturn[0] = getString (password);
+ }
+ }
+
+ int space = Cocoa.objc_msgSend (challenge, Cocoa.S_protectionSpace);
+ int host = Cocoa.objc_msgSend (space, Cocoa.S_host);
+ String hostString = getString (host) + ':';
+ int port = Cocoa.objc_msgSend (space, Cocoa.S_port);
+ hostString += port;
+ int realm = Cocoa.objc_msgSend (space, Cocoa.S_realm);
+ String realmString = getString (realm);
+ boolean result = showAuthenticationDialog (userReturn, passwordReturn, hostString, realmString);
+ int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender);
+ if (!result) {
+ Cocoa.objc_msgSend (challengeSender, Cocoa.S_cancelAuthenticationChallenge, challenge);
+ return;
+ }
+
+ int length = userReturn[0].length ();
+ char[] buffer = new char[length];
+ userReturn[0].getChars (0, length, buffer, 0);
+ int user = OS.CFStringCreateWithCharacters (0, buffer, length);
+ length = passwordReturn[0].length ();
+ buffer = new char[length];
+ passwordReturn[0].getChars (0, length, buffer, 0);
+ int password = OS.CFStringCreateWithCharacters (0, buffer, length);
+ int credential = Cocoa.objc_msgSend (Cocoa.C_NSURLCredential, Cocoa.S_credentialWithUser, user, password, Cocoa.NSURLCredentialPersistenceForSession);
+ Cocoa.objc_msgSend (challengeSender, Cocoa.S_useCredential, credential, challenge);
+ OS.CFRelease (password);
+ OS.CFRelease (user);
+}
+
+boolean showAuthenticationDialog (final String[] user, final String[] password, String host, String realm) {
+ final Shell shell = new Shell (browser.getShell ());
+ shell.setLayout (new GridLayout ());
+ String title = SWT.getMessage ("SWT_Authentication_Required"); //$NON-NLS-1$
+ shell.setText (title);
+ Label label = new Label (shell, SWT.WRAP);
+ label.setText (Compatibility.getMessage ("SWT_Enter_Username_and_Password", new String[] {realm, host})); //$NON-NLS-1$
+
+ GridData data = new GridData ();
+ Monitor monitor = browser.getMonitor ();
+ int maxWidth = monitor.getBounds ().width * 2 / 3;
+ int width = label.computeSize (SWT.DEFAULT, SWT.DEFAULT).x;
+ data.widthHint = Math.min (width, maxWidth);
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ label.setLayoutData (data);
+
+ Label userLabel = new Label (shell, SWT.NONE);
+ userLabel.setText (SWT.getMessage ("SWT_Username")); //$NON-NLS-1$
+
+ final Text userText = new Text (shell, SWT.BORDER);
+ if (user[0] != null) userText.setText (user[0]);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ userText.setLayoutData (data);
+
+ Label passwordLabel = new Label (shell, SWT.NONE);
+ passwordLabel.setText (SWT.getMessage ("SWT_Password")); //$NON-NLS-1$
+
+ final Text passwordText = new Text (shell, SWT.PASSWORD | SWT.BORDER);
+ if (password[0] != null) passwordText.setText (password[0]);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ passwordText.setLayoutData (data);
+
+ final boolean[] result = new boolean[1];
+ final Button[] buttons = new Button[2];
+ Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+ user[0] = userText.getText();
+ password[0] = passwordText.getText();
+ result[0] = event.widget == buttons[1];
+ shell.close();
+ }
+ };
+
+ Composite composite = new Composite (shell, SWT.NONE);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.END;
+ composite.setLayoutData (data);
+ composite.setLayout (new GridLayout (2, true));
+ buttons[0] = new Button (composite, SWT.PUSH);
+ buttons[0].setText (SWT.getMessage("SWT_Cancel")); //$NON-NLS-1$
+ buttons[0].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
+ buttons[0].addListener (SWT.Selection, listener);
+ buttons[1] = new Button (composite, SWT.PUSH);
+ buttons[1].setText (SWT.getMessage("SWT_OK")); //$NON-NLS-1$
+ buttons[1].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
+ buttons[1].addListener (SWT.Selection, listener);
+
+ shell.setDefaultButton (buttons[1]);
+ shell.pack ();
+ shell.open ();
+ Display display = browser.getDisplay ();
+ while (!shell.isDisposed ()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+
+ return result[0];
+}
+
+int identifierForInitialRequest(int request, int dataSource) {
+ final Display display = browser.getDisplay();
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = resourceCount;
+ progress.total = Math.max(resourceCount, MAX_PROGRESS);
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The widget ProgressBar currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncexec so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed())
+ listener.changed(progress);
+ }
+ }
+ );
+ }
+
+ /*
+ * Note. numberWithInt uses autorelease. The resulting object
+ * does not need to be released.
+ * identifier = [NSNumber numberWithInt: resourceCount++]
+ */
+ int identifier = Cocoa.objc_msgSend(Cocoa.C_NSNumber, Cocoa.S_numberWithInt, resourceCount++);
+
+ if (this.identifier == 0) {
+ int frame = Cocoa.objc_msgSend(dataSource, Cocoa.S_webFrame);
+ if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) this.identifier = identifier;
+ }
+ return identifier;
+
+}
+
+int willSendRequest(int identifier, int request, int redirectResponse, int dataSource) {
+ int url = Cocoa.objc_msgSend (request, Cocoa.S_URL);
+ boolean isFileURL = Cocoa.objc_msgSend (url, Cocoa.S_isFileURL) != 0;
+ if (isFileURL) {
+ int newRequest = Cocoa.objc_msgSend (request, Cocoa.S_mutableCopy);
+ Cocoa.objc_msgSend (newRequest, Cocoa.S_autorelease);
+ Cocoa.objc_msgSend (newRequest, Cocoa.S_setCachePolicy, Cocoa.NSURLRequestReloadIgnoringLocalCacheData);
+ return newRequest;
+ }
+ return request;
+}
+
+/* handleNotification */
+
+void handleNotification(int notification) {
+}
+
+/* UIDelegate */
+int createWebViewWithRequest(int request) {
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.required = true;
+ if (openWindowListeners != null) {
+ for (int i = 0; i < openWindowListeners.length; i++) {
+ openWindowListeners[i].open(newEvent);
+ }
+ }
+
+ int webView = 0;
+ Browser browser = null;
+ if (newEvent.browser != null && newEvent.browser.webBrowser instanceof Safari) {
+ browser = newEvent.browser;
+ }
+ if (browser != null && !browser.isDisposed()) {
+ webView = ((Safari)browser.webBrowser).webView;
+
+ if (request != 0) {
+ //mainFrame = [webView mainFrame];
+ int mainFrame= Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame);
+
+ //[mainFrame loadRequest:request];
+ Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadRequest, request);
+ }
+ }
+ return webView;
+}
+
+void webViewShow(int sender) {
+ /*
+ * Feature on WebKit. The Safari WebKit expects the application
+ * to create a new Window using the Objective C Cocoa API in response
+ * to UIDelegate.createWebViewWithRequest. The application is then
+ * expected to use Objective C Cocoa API to make this window visible
+ * when receiving the UIDelegate.webViewShow message. For some reason,
+ * a window created with the Carbon API hosting the new browser instance
+ * does not redraw until it has been resized. The fix is to increase the
+ * size of the Shell and restore it to its initial size.
+ */
+ Shell parent = browser.getShell();
+ Point pt = parent.getSize();
+ parent.setSize(pt.x+1, pt.y);
+ parent.setSize(pt.x, pt.y);
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ if (location != null) newEvent.location = location;
+ if (size != null) newEvent.size = size;
+ /*
+ * Feature in Safari. Safari's tool bar contains
+ * the address bar. The address bar is displayed
+ * if the tool bar is displayed. There is no separate
+ * notification for the address bar.
+ *
+ * Feature of OSX. The menu bar is always displayed.
+ * There is no notification to hide the menu bar.
+ */
+ newEvent.addressBar = toolBar;
+ newEvent.menuBar = true;
+ newEvent.statusBar = statusBar;
+ newEvent.toolBar = toolBar;
+ for (int i = 0; i < visibilityWindowListeners.length; i++) {
+ visibilityWindowListeners[i].show(newEvent);
+ }
+ location = null;
+ size = null;
+}
+
+void setFrame(int frame) {
+ float[] dest = new float[4];
+ OS.memmove(dest, frame, 16);
+ /* convert to SWT system coordinates */
+ Rectangle bounds = browser.getDisplay().getBounds();
+ location = new Point((int)dest[0], bounds.height - (int)dest[1] - (int)dest[3]);
+ size = new Point((int)dest[2], (int)dest[3]);
+}
+
+void webViewFocus() {
+}
+
+void webViewUnfocus() {
+}
+
+void runJavaScriptAlertPanelWithMessage(int message) {
+ int length = OS.CFStringGetLength(message);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(message, range, buffer);
+ String text = new String(buffer);
+
+ MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_WARNING);
+ messageBox.setText("Javascript"); //$NON-NLS-1$
+ messageBox.setMessage(text);
+ messageBox.open();
+}
+
+int runJavaScriptConfirmPanelWithMessage(int message) {
+ int length = OS.CFStringGetLength(message);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(message, range, buffer);
+ String text = new String(buffer);
+
+ MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.CANCEL | SWT.ICON_QUESTION);
+ messageBox.setText("Javascript"); //$NON-NLS-1$
+ messageBox.setMessage(text);
+ return messageBox.open() == SWT.OK ? 1 : 0;
+}
+
+void runOpenPanelForFileButtonWithResultListener(int resultListener) {
+ FileDialog dialog = new FileDialog(browser.getShell(), SWT.NONE);
+ String result = dialog.open();
+ if (result == null) {
+ Cocoa.objc_msgSend(resultListener, Cocoa.S_cancel);
+ return;
+ }
+ int length = result.length();
+ char[] buffer = new char[length];
+ result.getChars(0, length, buffer, 0);
+ int filename = OS.CFStringCreateWithCharacters(0, buffer, length);
+ Cocoa.objc_msgSend(resultListener, Cocoa.S_chooseFilename, filename);
+ OS.CFRelease(filename);
+}
+
+void webViewClose() {
+ Shell parent = browser.getShell();
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ for (int i = 0; i < closeWindowListeners.length; i++) {
+ closeWindowListeners[i].close(newEvent);
+ }
+ browser.dispose();
+ if (parent.isDisposed()) return;
+ /*
+ * Feature on WebKit. The Safari WebKit expects the application
+ * to create a new Window using the Objective C Cocoa API in response
+ * to UIDelegate.createWebViewWithRequest. The application is then
+ * expected to use Objective C Cocoa API to make this window visible
+ * when receiving the UIDelegate.webViewShow message. For some reason,
+ * a window created with the Carbon API hosting the new browser instance
+ * does not redraw until it has been resized. The fix is to increase the
+ * size of the Shell and restore it to its initial size.
+ */
+ Point pt = parent.getSize();
+ parent.setSize(pt.x+1, pt.y);
+ parent.setSize(pt.x, pt.y);
+}
+
+int contextMenuItemsForElement(int element, int defaultMenuItems) {
+ org.eclipse.swt.internal.carbon.Point pt = new org.eclipse.swt.internal.carbon.Point();
+ OS.GetGlobalMouse(pt);
+ Event event = new Event();
+ event.x = pt.h;
+ event.y = pt.v;
+ browser.notifyListeners(SWT.MenuDetect, event);
+ if (!event.doit || browser.isDisposed()) return 0;
+ Menu menu = browser.getMenu();
+ if (menu != null && !menu.isDisposed()) {
+ if (event.x != pt.h || event.y != pt.v) {
+ menu.setLocation(event.x, event.y);
+ }
+ menu.setVisible(true);
+ return 0;
+ }
+ return defaultMenuItems;
+}
+
+void setStatusBarVisible(int visible) {
+ /* Note. Webkit only emits the notification when the status bar should be hidden. */
+ statusBar = visible != 0;
+}
+
+void setStatusText(int text) {
+ int length = OS.CFStringGetLength(text);
+ if (length == 0) return;
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(text, range, buffer);
+
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = new String(buffer);
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+}
+
+void setResizable(int visible) {
+}
+
+void setToolbarsVisible(int visible) {
+ /* Note. Webkit only emits the notification when the tool bar should be hidden. */
+ toolBar = visible != 0;
+}
+
+void mouseDidMoveOverElement (int elementInformation, int modifierFlags) {
+ if (elementInformation == 0) return;
+ if (!browser.isEnabled ()) return;
+
+ int length = WebElementLinkURLKey.length();
+ char[] chars = new char[length];
+ WebElementLinkURLKey.getChars(0, length, chars, 0);
+ int key = OS.CFStringCreateWithCharacters(0, chars, length);
+ int value = Cocoa.objc_msgSend(elementInformation, Cocoa.S_valueForKey, key);
+ OS.CFRelease(key);
+ if (value == 0) {
+ /* not currently over a link */
+ if (lastHoveredLinkURL == null) return;
+ lastHoveredLinkURL = null;
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = ""; //$NON-NLS-1$
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ return;
+ }
+
+ int stringPtr = Cocoa.objc_msgSend(value, Cocoa.S_absoluteString);
+ length = OS.CFStringGetLength(stringPtr);
+ String urlString;
+ if (length == 0) {
+ urlString = ""; //$NON-NLS-1$
+ } else {
+ chars = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(stringPtr, range, chars);
+ urlString = new String(chars);
+ }
+ if (urlString.equals(lastHoveredLinkURL)) return;
+
+ lastHoveredLinkURL = urlString;
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = urlString;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+}
+
+/* PolicyDelegate */
+
+void decidePolicyForMIMEType(int type, int request, int frame, int listener) {
+ boolean canShow = Cocoa.objc_msgSend(Cocoa.C_WebView, Cocoa.S_canShowMIMEType, type) != 0;
+ Cocoa.objc_msgSend(listener, canShow ? Cocoa.S_use : Cocoa.S_download);
+}
+
+void decidePolicyForNavigationAction(int actionInformation, int request, int frame, int listener) {
+ int url = Cocoa.objc_msgSend(request, Cocoa.S_URL);
+ if (url == 0) {
+ /* indicates that a URL with an invalid format was specified */
+ Cocoa.objc_msgSend(listener, Cocoa.S_ignore);
+ return;
+ }
+ int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString);
+ int length = OS.CFStringGetLength(s);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(s, range, buffer);
+ String url2 = new String(buffer);
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ if (url2.startsWith (URI_APPLEWEBDATA)) {
+ /* listeners should not be notified of internal transitions like this */
+ Cocoa.objc_msgSend(listener, Cocoa.S_use);
+ } else {
+ LocationEvent newEvent = new LocationEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.location = url2;
+ newEvent.doit = true;
+ if (locationListeners != null) {
+ changingLocation = true;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changing(newEvent);
+ }
+ changingLocation = false;
+ }
+ if (newEvent.doit) {
+ if (jsEnabledChanged) {
+ jsEnabledChanged = false;
+ if (preferences == 0) {
+ preferences = Cocoa.objc_msgSend (Cocoa.C_WebPreferences, Cocoa.S_alloc);
+ Cocoa.objc_msgSend (preferences, Cocoa.S_init);
+ Cocoa.objc_msgSend (webView, Cocoa.S_setPreferences, preferences);
+ }
+ Cocoa.objc_msgSend (preferences, Cocoa.S_setJavaScriptEnabled, jsEnabled ? 1 : 0);
+ }
+ lastNavigateURL = url2;
+ }
+ Cocoa.objc_msgSend(listener, newEvent.doit ? Cocoa.S_use : Cocoa.S_ignore);
+ }
+
+ if (html != null && !browser.isDisposed()) {
+ String html = this.html;
+ this.html = null;
+ _setText(html);
+ }
+}
+
+void decidePolicyForNewWindowAction(int actionInformation, int request, int frameName, int listener) {
+ Cocoa.objc_msgSend(listener, Cocoa.S_use);
+}
+
+void unableToImplementPolicyWithError(int error, int frame) {
+}
+
+/* WebDownload */
+
+void decideDestinationWithSuggestedFilename (int download, int filename) {
+ int length = OS.CFStringGetLength(filename);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(filename, range, buffer);
+ String name = new String(buffer);
+
+ /*
+ * Bug in Safari. As of OSX 10.5.5, showing the file dialog here invokes this
+ * callback a second time when the file dialog runs the event loop, which
+ * always leads to a crash. The workaround is to choose a location to save
+ * the file without showing the file dialog.
+ */
+ String path = null;
+ if (OS.VERSION >= 0x1055) {
+ int array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDesktopDirectory, Cocoa.NSAllDomainsMask, true);
+ int count = Cocoa.objc_msgSend (array, Cocoa.S_count);
+ if (count == 0) { /* should never happen */
+ array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDownloadsDirectory, Cocoa.NSAllDomainsMask, true);
+ count = Cocoa.objc_msgSend (array, Cocoa.S_count);
+ if (count == 0) {
+ array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDocumentDirectory, Cocoa.NSAllDomainsMask, true);
+ count = Cocoa.objc_msgSend (array, Cocoa.S_count);
+ if (count == 0) {
+ Cocoa.objc_msgSend (download, Cocoa.S_cancel);
+ return;
+ }
+ }
+ }
+ int string = Cocoa.objc_msgSend (array, Cocoa.S_objectAtIndex, 0);
+ length = OS.CFStringGetLength (string);
+ buffer = new char[length];
+ range = new CFRange ();
+ range.length = length;
+ OS.CFStringGetCharacters (string, range, buffer);
+ path = new String (buffer) + '/' + name;
+ } else {
+ FileDialog dialog = new FileDialog(browser.getShell(), SWT.SAVE);
+ dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$
+ dialog.setFileName(name);
+ path = dialog.open();
+ }
+
+ if (path == null) {
+ /* cancel pressed */
+ Cocoa.objc_msgSend(download, Cocoa.S_cancel);
+ return;
+ }
+ length = path.length();
+ char[] chars = new char[length];
+ path.getChars(0, length, chars, 0);
+ int result = OS.CFStringCreateWithCharacters(0, chars, length);
+ Cocoa.objc_msgSend(download, Cocoa.S_setDestinationAllowOverwrite, result, 1);
+ OS.CFRelease(result);
+}
+
+/* DOMEventListener */
+
+void handleEvent(int evt) {
+ if (!browser.isEnabled ()) return;
+
+ int type = Cocoa.objc_msgSend(evt, Cocoa.S_type);
+ int length = OS.CFStringGetLength(type);
+ char[] buffer = new char[length];
+ CFRange range = new CFRange();
+ range.length = length;
+ OS.CFStringGetCharacters(type, range, buffer);
+ String typeString = new String(buffer);
+
+ if (typeString.equals(DOMEVENT_FOCUSIN)) {
+ hasNewFocusElement = true;
+ return;
+ }
+ if (typeString.equals(DOMEVENT_FOCUSOUT)) {
+ hasNewFocusElement = false;
+ return;
+ }
+
+ boolean ctrl = Cocoa.objc_msgSend(evt, Cocoa.S_ctrlKey) != 0;
+ boolean shift = Cocoa.objc_msgSend(evt, Cocoa.S_shiftKey) != 0;
+ boolean alt = Cocoa.objc_msgSend(evt, Cocoa.S_altKey) != 0;
+ boolean meta = Cocoa.objc_msgSend(evt, Cocoa.S_metaKey) != 0;
+
+ if (DOMEVENT_KEYDOWN.equals(typeString) || DOMEVENT_KEYUP.equals(typeString)) {
+ int keyCode = Cocoa.objc_msgSend(evt, Cocoa.S_keyCode);
+ int charCode = Cocoa.objc_msgSend(evt, Cocoa.S_charCode);
+
+ Event keyEvent = new Event();
+ keyEvent.widget = browser;
+ if (DOMEVENT_KEYDOWN.equals(typeString)) {
+ keyEvent.type = SWT.KeyDown;
+ } else {
+ keyEvent.type = SWT.KeyUp;
+ }
+ keyEvent.keyCode = translateKey(keyCode);
+ /*
+ * Safari maps the Delete key's character to 0xf728. Detect
+ * this key and set its character to SWT.DEL so that the
+ * Browser's key events are consistent with other controls.
+ */
+ if (keyEvent.keyCode == SWT.DEL) {
+ keyEvent.character = SWT.DEL;
+ } else {
+ keyEvent.character = (char)charCode;
+ }
+ keyEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ browser.notifyListeners(keyEvent.type, keyEvent);
+ if (browser.isDisposed()) {
+ Cocoa.objc_msgSend(evt, Cocoa.S_preventDefault);
+ return;
+ }
+
+ boolean doit = keyEvent.doit;
+ /*
+ * Bug in Safari. As a result of using HIWebViewCreate on OSX versions < 10.5 (Leopard), attempting
+ * to traverse out of Safari backwards (Shift+Tab) leaves it in a strange state where Safari no
+ * longer has focus but still receives keys. The Carbon-based Safari examples have the same
+ * problem. The workaround is to only allow forward Tab traversals in the Browser on OSX < 10.5.
+ */
+ if (doit && OS.VERSION < 0x1050 && keyEvent.keyCode == SWT.TAB && (keyEvent.stateMask & SWT.SHIFT) != 0) {
+ doit = false;
+ }
+ if (!doit) {
+ Cocoa.objc_msgSend(evt, Cocoa.S_preventDefault);
+ } else {
+ if (!hasNewFocusElement && keyEvent.keyCode == SWT.TAB && DOMEVENT_KEYUP.equals(typeString)) {
+ browser.traverse(SWT.TRAVERSE_TAB_NEXT);
+ hasNewFocusElement = false;
+ }
+ }
+ return;
+ }
+
+ /* mouse event */
+
+ int clientX = Cocoa.objc_msgSend(evt, Cocoa.S_clientX);
+ int clientY = Cocoa.objc_msgSend(evt, Cocoa.S_clientY);
+ int detail = Cocoa.objc_msgSend(evt, Cocoa.S_detail);
+
+ Event mouseEvent = new Event ();
+ mouseEvent.widget = browser;
+ mouseEvent.x = clientX; mouseEvent.y = clientY;
+ mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+
+ if (DOMEVENT_MOUSEDOWN.equals (typeString)) {
+ mouseEvent.type = SWT.MouseDown;
+ int button = Cocoa.objc_msgSend(evt, Cocoa.S_button);
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ } else if (DOMEVENT_MOUSEUP.equals (typeString)) {
+ mouseEvent.type = SWT.MouseUp;
+ int button = Cocoa.objc_msgSend(evt, Cocoa.S_button);
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ switch (mouseEvent.button) {
+ case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
+ case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
+ case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
+ case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
+ case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
+ }
+ } else if (DOMEVENT_MOUSEMOVE.equals (typeString)) {
+ /*
+ * Feature in Safari. Spurious and redundant mousemove events are received in
+ * various contexts, including following every MouseUp. The workaround is to
+ * not fire MouseMove events whose x and y values match the last MouseMove.
+ */
+ if (mouseEvent.x == lastMouseMoveX && mouseEvent.y == lastMouseMoveY) return;
+ mouseEvent.type = SWT.MouseMove;
+ lastMouseMoveX = mouseEvent.x; lastMouseMoveY = mouseEvent.y;
+ } else if (DOMEVENT_MOUSEWHEEL.equals (typeString)) {
+ mouseEvent.type = SWT.MouseWheel;
+ int delta = Cocoa.objc_msgSend(evt, Cocoa.S_wheelDelta);
+ mouseEvent.count = delta / 120;
+ }
+
+ browser.notifyListeners (mouseEvent.type, mouseEvent);
+ if (browser.isDisposed()) return;
+ if (detail == 2 && DOMEVENT_MOUSEDOWN.equals (typeString)) {
+ int button = Cocoa.objc_msgSend(evt, Cocoa.S_button);
+ mouseEvent = new Event ();
+ mouseEvent.widget = browser;
+ mouseEvent.x = clientX; mouseEvent.y = clientY;
+ mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ mouseEvent.type = SWT.MouseDoubleClick;
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ browser.notifyListeners (mouseEvent.type, mouseEvent);
+ }
+}
+
+/* external */
+
+Object convertToJava (int value) {
+ if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_NSString) != 0) {
+ int length = Cocoa.objc_msgSend (value, Cocoa.S_length);
+ char[] buffer = new char[length];
+ Cocoa.objc_msgSend (value, Cocoa.S_getCharacters_, buffer);
+ return new String (buffer);
+ }
+ if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_NSNumber) != 0) {
+ int ptr = Cocoa.objc_msgSend (value, Cocoa.S_objCType);
+ byte[] type = new byte[1];
+ OS.memmove (type, ptr, 1);
+ if (type[0] == 'c' || type[0] == 'B') {
+ int result = Cocoa.objc_msgSend (value, Cocoa.S_boolValue);
+ return new Boolean (result != 0);
+ }
+ if ("islqISLQfd".indexOf (type[0]) != -1) { //$NON-NLS-1$
+ double result = Cocoa.objc_msgSend_fpret (value, Cocoa.S_doubleValue);
+ return new Double (result);
+ }
+ }
+ if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_WebScriptObject) != 0) {
+ String string = "length"; //$NON-NLS-1$
+ char[] chars = new char[string.length ()];
+ string.getChars (0, chars.length, chars, 0);
+ int str = OS.CFStringCreateWithCharacters (0, chars, chars.length);
+ int numberValue = Cocoa.objc_msgSend (value, Cocoa.S_valueForKey, str);
+ OS.CFRelease (str);
+ int length = Cocoa.objc_msgSend (numberValue, Cocoa.S_intValue);
+ Object[] arguments = new Object[length];
+ for (int i = 0; i < length; i++) {
+ int current = Cocoa.objc_msgSend (value, Cocoa.S_webScriptValueAtIndex, i);
+ if (current != 0) {
+ arguments[i] = convertToJava (current);
+ }
+ }
+ return arguments;
+ }
+ if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_WebUndefined) != 0) {
+ return null;
+ }
+
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ return null;
+}
+
+int convertToJS (Object value) {
+ if (value == null) {
+ return Cocoa.objc_msgSend (Cocoa.C_WebUndefined, Cocoa.S_undefined);
+ }
+ if (value instanceof String) {
+ String result = (String)value;
+ char[] chars = new char[result.length ()];
+ result.getChars (0, chars.length, chars, 0);
+ return OS.CFStringCreateWithCharacters (0, chars, chars.length);
+ }
+ if (value instanceof Boolean) {
+ int booleanValue = ((Boolean)value).booleanValue () ? 1 : 0;
+ return Cocoa.objc_msgSend (Cocoa.C_NSNumber, Cocoa.S_numberWithBool, booleanValue);
+ }
+ if (value instanceof Number) {
+ double doubleValue = ((Number)value).doubleValue ();
+ return Cocoa.objc_msgSend (Cocoa.C_NSNumber, Cocoa.S_numberWithDouble, doubleValue);
+ }
+ if (value instanceof Object[]) {
+ Object[] arrayValue = (Object[])value;
+ int length = arrayValue.length;
+ if (length > 0) {
+ int array = Cocoa.objc_msgSend (Cocoa.C_NSMutableArray, Cocoa.S_arrayWithCapacity, length);
+ for (int i = 0; i < length; i++) {
+ Object currentObject = arrayValue[i];
+ int jsObject = convertToJS (currentObject);
+ Cocoa.objc_msgSend (array, Cocoa.S_addObject, jsObject);
+ }
+ return array;
+ }
+ }
+ SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
+ return 0;
+}
+
+int /*long*/ callJava (int /*long*/ index, int /*long*/ args, int /*long*/ arg1) {
+ Object returnValue = null;
+ if (Cocoa.objc_msgSend (index, Cocoa.S_isKindOfClass, Cocoa.C_NSNumber) != 0) {
+ int functionIndex = Cocoa.objc_msgSend (index, Cocoa.S_intValue);
+ Object key = new Integer (functionIndex);
+ BrowserFunction function = (BrowserFunction)functions.get (key);
+ if (function != null) {
+ try {
+ Object temp = convertToJava (args);
+ if (temp instanceof Object[]) {
+ Object[] arguments = (Object[])temp;
+ try {
+ returnValue = function.function (arguments);
+ } catch (Exception e) {
+ /* exception during function invocation */
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ /* invalid argument value type */
+ if (function.isEvaluate) {
+ /* notify the evaluate function so that a java exception can be thrown */
+ function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
+ }
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ }
+ try {
+ return convertToJS (returnValue);
+ } catch (SWTException e) {
+ return convertToJS (WebBrowser.CreateErrorString (e.getLocalizedMessage ()));
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/cocoa/org/eclipse/swt/browser/Safari.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/cocoa/org/eclipse/swt/browser/Safari.java
new file mode 100755
index 0000000000..dbc068b3a3
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/cocoa/org/eclipse/swt/browser/Safari.java
@@ -0,0 +1,1572 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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.Enumeration;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.cocoa.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+class Safari extends WebBrowser {
+ WebView webView;
+ WebPreferences preferences;
+ SWTWebViewDelegate delegate;
+ boolean changingLocation;
+ String lastHoveredLinkURL, lastNavigateURL;
+ String html;
+ int /*long*/ identifier;
+ int resourceCount;
+ String url = ""; //$NON-NLS-1$
+ Point location;
+ Point size;
+ boolean statusBar = true, toolBar = true, ignoreDispose;
+ int lastMouseMoveX, lastMouseMoveY;
+ //TEMPORARY CODE
+// boolean doit;
+
+ static int /*long*/ delegateClass;
+ static boolean Initialized;
+ // the following Callbacks are never freed
+ static Callback Callback3, Callback4, Callback5, Callback6, Callback7;
+
+ static final int MIN_SIZE = 16;
+ static final int MAX_PROGRESS = 100;
+ static final String WebElementLinkURLKey = "WebElementLinkURL"; //$NON-NLS-1$
+ static final String AGENT_STRING = "Safari/unknown"; //$NON-NLS-1$
+ static final String URI_FROMMEMORY = "file:///"; //$NON-NLS-1$
+ static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
+ static final String PROTOCOL_HTTP = "http://"; //$NON-NLS-1$
+ static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+ static final String HEADER_SETCOOKIE = "Set-Cookie"; //$NON-NLS-1$
+ static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$
+ static final String SAFARI_EVENTS_FIX_KEY = "org.eclipse.swt.internal.safariEventsFix"; //$NON-NLS-1$
+ static final byte[] SWT_OBJECT = {'S', 'W', 'T', '_', 'O', 'B', 'J', 'E', 'C', 'T', '\0'};
+
+ /* event strings */
+ static final String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
+ static final String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
+ static final String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+
+ static {
+ NativeClearSessions = new Runnable() {
+ public void run() {
+ NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage();
+ NSArray cookies = storage.cookies();
+ int count = (int)/*64*/cookies.count ();
+ for (int i = 0; i < count; i++) {
+ NSHTTPCookie cookie = new NSHTTPCookie(cookies.objectAtIndex(i));
+ if (cookie.isSessionOnly()) {
+ storage.deleteCookie(cookie);
+ }
+ }
+ }
+ };
+
+ NativeGetCookie = new Runnable () {
+ public void run () {
+ NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage ();
+ NSURL url = NSURL.URLWithString (NSString.stringWith (CookieUrl));
+ NSArray cookies = storage.cookiesForURL (url);
+ int count = (int)/*64*/cookies.count ();
+ if (count == 0) return;
+
+ NSString name = NSString.stringWith (CookieName);
+ for (int i = 0; i < count; i++) {
+ NSHTTPCookie current = new NSHTTPCookie (cookies.objectAtIndex (i));
+ if (current.name ().compare (name) == OS.NSOrderedSame) {
+ CookieValue = current.value ().getString ();
+ return;
+ }
+ }
+ }
+ };
+
+ NativeSetCookie = new Runnable () {
+ public void run () {
+ NSURL url = NSURL.URLWithString (NSString.stringWith (CookieUrl));
+ NSMutableDictionary headers = NSMutableDictionary.dictionaryWithCapacity (1);
+ headers.setValue (NSString.stringWith (CookieValue), NSString.stringWith (HEADER_SETCOOKIE));
+ NSArray cookies = NSHTTPCookie.cookiesWithResponseHeaderFields (headers, url);
+ if (cookies.count () == 0) return;
+ NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage ();
+ NSHTTPCookie cookie = new NSHTTPCookie (cookies.objectAtIndex (0));
+ storage.setCookie (cookie);
+ CookieResult = true;
+ }
+ };
+ }
+
+public void create (Composite parent, int style) {
+ if (delegateClass == 0) {
+ Class safariClass = this.getClass();
+ Callback3 = new Callback(safariClass, "browserProc", 3); //$NON-NLS-1$
+ int /*long*/ proc3 = Callback3.getAddress();
+ if (proc3 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ Callback4 = new Callback(safariClass, "browserProc", 4); //$NON-NLS-1$
+ int /*long*/ proc4 = Callback4.getAddress();
+ if (proc4 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ Callback5 = new Callback(safariClass, "browserProc", 5); //$NON-NLS-1$
+ int /*long*/ proc5 = Callback5.getAddress();
+ if (proc5 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ Callback6 = new Callback(safariClass, "browserProc", 6); //$NON-NLS-1$
+ int /*long*/ proc6 = Callback6.getAddress();
+ if (proc6 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ Callback7 = new Callback(safariClass, "browserProc", 7); //$NON-NLS-1$
+ int /*long*/ proc7 = Callback7.getAddress();
+ if (proc7 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ int /*long*/ setFrameProc = OS.CALLBACK_webView_setFrame_(proc4);
+ if (setFrameProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+ String className = "SWTWebViewDelegate"; //$NON-NLS-1$
+ byte[] types = {'*','\0'};
+ int size = C.PTR_SIZEOF, align = C.PTR_SIZEOF == 4 ? 2 : 3;
+ delegateClass = OS.objc_allocateClassPair (OS.class_NSObject, className, 0);
+
+ OS.class_addIvar(delegateClass, SWT_OBJECT, size, (byte)align, types);
+ OS.class_addMethod(delegateClass, OS.sel_webView_didChangeLocationWithinPageForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_didFailProvisionalLoadWithError_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_didFinishLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_didReceiveTitle_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_didStartProvisionalLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_didCommitLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_resource_didFinishLoadingFromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_resource_didReceiveAuthenticationChallenge_fromDataSource_, proc6, "@:@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_, proc6, "@:@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_identifierForInitialRequest_fromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_, proc7, "@:@@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_createWebViewWithRequest_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webViewShow_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webViewClose_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_setStatusBarVisible_, proc4, "@:@B"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_setResizable_, proc4, "@:@B"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_setToolbarsVisible_, proc4, "@:@B"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_setStatusText_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webViewFocus_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webViewUnfocus_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptAlertPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptConfirmPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_runOpenPanelForFileButtonWithResultListener_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_mouseDidMoveOverElement_modifierFlags_, proc5, "@:@@I"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_printFrameView_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_unableToImplementPolicyWithError_frame_, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_download_decideDestinationWithSuggestedFilename_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_handleEvent_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_setFrame_, setFrameProc, "@:@{NSRect}"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_webView_windowScriptObjectAvailable_, proc4, "@:@@"); //$NON-NLS-1$
+ OS.class_addMethod(delegateClass, OS.sel_callJava, proc5, "@:@@@"); //$NON-NLS-1$
+ OS.objc_registerClassPair(delegateClass);
+
+ int /*long*/ metaClass = OS.objc_getMetaClass (className);
+ OS.class_addMethod(metaClass, OS.sel_isSelectorExcludedFromWebScript_, proc3, "@:@"); //$NON-NLS-1$
+ OS.class_addMethod(metaClass, OS.sel_webScriptNameForSelector_, proc3, "@:@"); //$NON-NLS-1$
+ }
+
+ /*
+ * Override the default event mechanism to not send key events so
+ * that the browser can send them by listening to the DOM instead.
+ */
+ browser.setData(SAFARI_EVENTS_FIX_KEY);
+
+ WebView webView = (WebView)new WebView().alloc();
+ if (webView == null) SWT.error(SWT.ERROR_NO_HANDLES);
+ webView.initWithFrame(browser.view.frame(), null, null);
+ webView.setAutoresizingMask(OS.NSViewWidthSizable | OS.NSViewHeightSizable);
+ final SWTWebViewDelegate delegate = (SWTWebViewDelegate)new SWTWebViewDelegate().alloc().init();
+ Display display = browser.getDisplay();
+ display.setData(ADD_WIDGET_KEY, new Object[] {delegate, browser});
+ this.delegate = delegate;
+ this.webView = webView;
+ browser.view.addSubview(webView);
+
+ Listener listener = new Listener() {
+ public void handleEvent(Event e) {
+ switch (e.type) {
+ case SWT.FocusIn:
+ Safari.this.webView.window().makeFirstResponder(Safari.this.webView);
+ break;
+ case SWT.Dispose: {
+ /* make this handler run after other dispose listeners */
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (e.type, e);
+ e.type = SWT.NONE;
+
+ e.display.setData(ADD_WIDGET_KEY, new Object[] {delegate, null});
+
+ Safari.this.webView.setFrameLoadDelegate(null);
+ Safari.this.webView.setResourceLoadDelegate(null);
+ Safari.this.webView.setUIDelegate(null);
+ Safari.this.webView.setPolicyDelegate(null);
+ Safari.this.webView.setDownloadDelegate(null);
+
+ Safari.this.webView.release();
+ Safari.this.webView = null;
+ Safari.this.delegate.release();
+ Safari.this.delegate = null;
+ html = null;
+ lastHoveredLinkURL = lastNavigateURL = null;
+
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ ((BrowserFunction)elements.nextElement ()).dispose (false);
+ }
+ functions = null;
+
+ if (preferences != null) preferences.release ();
+ preferences = null;
+ break;
+ }
+ }
+ }
+ };
+ browser.addListener(SWT.Dispose, listener);
+ /* Needed to be able to tab into the browser */
+ browser.addListener(SWT.KeyDown, listener);
+ browser.addListener(SWT.FocusIn, listener);
+
+ webView.setFrameLoadDelegate(delegate);
+ webView.setResourceLoadDelegate(delegate);
+ webView.setUIDelegate(delegate);
+ webView.setPolicyDelegate(delegate);
+ webView.setDownloadDelegate(delegate);
+ webView.setApplicationNameForUserAgent(NSString.stringWith(AGENT_STRING));
+
+ if (!Initialized) {
+ Initialized = true;
+ /* disable applets */
+ WebPreferences.standardPreferences().setJavaEnabled(false);
+ }
+}
+
+public boolean back() {
+ html = null;
+ return webView.goBack();
+}
+
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+ if (id == delegateClass) {
+ if (sel == OS.sel_isSelectorExcludedFromWebScript_) {
+ return isSelectorExcludedFromWebScript (arg0) ? 1 : 0;
+ } else if (sel == OS.sel_webScriptNameForSelector_) {
+ return webScriptNameForSelector (arg0);
+ }
+ }
+
+ Widget widget = Display.getCurrent().findWidget(id);
+ if (widget == null) return 0;
+ Safari safari = (Safari)((Browser)widget).webBrowser;
+ if (sel == OS.sel_webViewShow_) {
+ safari.webViewShow(arg0);
+ } else if (sel == OS.sel_webViewClose_) {
+ safari.webViewClose(arg0);
+ } else if (sel == OS.sel_webViewFocus_) {
+ safari.webViewFocus(arg0);
+ } else if (sel == OS.sel_webViewUnfocus_) {
+ safari.webViewUnfocus(arg0);
+ } else if (sel == OS.sel_handleEvent_) {
+ safari.handleEvent(arg0);
+ }
+ return 0;
+}
+
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+ Widget widget = Display.getCurrent().findWidget(id);
+ if (widget == null) return 0;
+ Safari safari = (Safari)((Browser)widget).webBrowser;
+ if (sel == OS.sel_webView_didChangeLocationWithinPageForFrame_) {
+ safari.webView_didChangeLocationWithinPageForFrame(arg0, arg1);
+ } else if (sel == OS.sel_webView_didFinishLoadForFrame_) {
+ safari.webView_didFinishLoadForFrame(arg0, arg1);
+ } else if (sel == OS.sel_webView_didStartProvisionalLoadForFrame_) {
+ safari.webView_didStartProvisionalLoadForFrame(arg0, arg1);
+ } else if (sel == OS.sel_webView_didCommitLoadForFrame_) {
+ safari.webView_didCommitLoadForFrame(arg0, arg1);
+ } else if (sel == OS.sel_webView_setFrame_) {
+ safari.webView_setFrame(arg0, arg1);
+ } else if (sel == OS.sel_webView_createWebViewWithRequest_) {
+ return safari.webView_createWebViewWithRequest(arg0, arg1);
+ } else if (sel == OS.sel_webView_setStatusBarVisible_) {
+ safari.webView_setStatusBarVisible(arg0, arg1 != 0);
+ } else if (sel == OS.sel_webView_setResizable_) {
+ safari.webView_setResizable(arg0, arg1 != 0);
+ } else if (sel == OS.sel_webView_setStatusText_) {
+ safari.webView_setStatusText(arg0, arg1);
+ } else if (sel == OS.sel_webView_setToolbarsVisible_) {
+ safari.webView_setToolbarsVisible(arg0, arg1 != 0);
+ } else if (sel == OS.sel_webView_runJavaScriptAlertPanelWithMessage_) {
+ safari.webView_runJavaScriptAlertPanelWithMessage(arg0, arg1);
+ } else if (sel == OS.sel_webView_runJavaScriptConfirmPanelWithMessage_) {
+ return safari.webView_runJavaScriptConfirmPanelWithMessage(arg0, arg1);
+ } else if (sel == OS.sel_webView_runOpenPanelForFileButtonWithResultListener_) {
+ safari.webView_runOpenPanelForFileButtonWithResultListener(arg0, arg1);
+ } else if (sel == OS.sel_download_decideDestinationWithSuggestedFilename_) {
+ safari.download_decideDestinationWithSuggestedFilename(arg0, arg1);
+ } else if (sel == OS.sel_webView_printFrameView_) {
+ safari.webView_printFrameView(arg0, arg1);
+ } else if (sel == OS.sel_webView_windowScriptObjectAvailable_) {
+ safari.webView_windowScriptObjectAvailable (arg0, arg1);
+ }
+ return 0;
+}
+
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2) {
+ Widget widget = Display.getCurrent().findWidget(id);
+ if (widget == null) return 0;
+ Safari safari = (Safari)((Browser)widget).webBrowser;
+ if (sel == OS.sel_webView_didFailProvisionalLoadWithError_forFrame_) {
+ safari.webView_didFailProvisionalLoadWithError_forFrame(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_didReceiveTitle_forFrame_) {
+ safari.webView_didReceiveTitle_forFrame(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_resource_didFinishLoadingFromDataSource_) {
+ safari.webView_resource_didFinishLoadingFromDataSource(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_identifierForInitialRequest_fromDataSource_) {
+ return safari.webView_identifierForInitialRequest_fromDataSource(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_) {
+ return safari.webView_contextMenuItemsForElement_defaultMenuItems(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_mouseDidMoveOverElement_modifierFlags_) {
+ safari.webView_mouseDidMoveOverElement_modifierFlags(arg0, arg1, arg2);
+ } else if (sel == OS.sel_webView_unableToImplementPolicyWithError_frame_) {
+ safari.webView_unableToImplementPolicyWithError_frame(arg0, arg1, arg2);
+ } else if (sel == OS.sel_callJava) {
+ id result = safari.callJava (arg0, arg1, arg2);
+ return result == null ? 0 : result.id;
+ }
+ return 0;
+}
+
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2, int /*long*/ arg3) {
+ Widget widget = Display.getCurrent().findWidget(id);
+ if (widget == null) return 0;
+ Safari safari = (Safari)((Browser)widget).webBrowser;
+ if (sel == OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_) {
+ safari.webView_resource_didFailLoadingWithError_fromDataSource(arg0, arg1, arg2, arg3);
+ } else if (sel == OS.sel_webView_resource_didReceiveAuthenticationChallenge_fromDataSource_) {
+ safari.webView_resource_didReceiveAuthenticationChallenge_fromDataSource(arg0, arg1, arg2, arg3);
+ }
+ return 0;
+}
+
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1, int /*long*/ arg2, int /*long*/ arg3, int /*long*/ arg4) {
+ Widget widget = Display.getCurrent().findWidget(id);
+ if (widget == null) return 0;
+ Safari safari = (Safari)((Browser)widget).webBrowser;
+ if (sel == OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_) {
+ return safari.webView_resource_willSendRequest_redirectResponse_fromDataSource(arg0, arg1, arg2, arg3, arg4);
+ } else if (sel == OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_) {
+ safari.webView_decidePolicyForMIMEType_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
+ } else if (sel == OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_) {
+ safari.webView_decidePolicyForNavigationAction_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
+ } else if (sel == OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_) {
+ safari.webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(arg0, arg1, arg2, arg3, arg4);
+ }
+ return 0;
+}
+
+static boolean isSelectorExcludedFromWebScript (int /*long*/ aSelector) {
+ return aSelector != OS.sel_callJava;
+}
+
+static int /*long*/ webScriptNameForSelector (int /*long*/ aSelector) {
+ if (aSelector == OS.sel_callJava) {
+ return NSString.stringWith ("callJava").id; //$NON-NLS-1$
+ }
+ return 0;
+}
+
+public boolean execute (String script) {
+ return webView.stringByEvaluatingJavaScriptFromString (NSString.stringWith (script)) != null;
+}
+
+public boolean forward () {
+ html = null;
+ return webView.goForward();
+}
+
+public String getBrowserType () {
+ return "safari"; //$NON-NLS-1$
+}
+
+public String getText() {
+ WebFrame mainFrame = webView.mainFrame();
+ WebDataSource dataSource = mainFrame.dataSource();
+ if (dataSource == null) return ""; //$NON-NLS-1$
+ WebDocumentRepresentation representation = dataSource.representation();
+ if (representation == null) return ""; //$NON-NLS-1$
+ NSString source = representation.documentSource();
+ if (source == null) return ""; //$NON-NLS-1$
+ return source.getString();
+}
+
+public String getUrl() {
+ return url;
+}
+
+public boolean isBackEnabled() {
+ return webView.canGoBack();
+}
+
+public boolean isForwardEnabled() {
+ return webView.canGoForward();
+}
+
+public void refresh() {
+ webView.reload(null);
+}
+
+public boolean setText(String html) {
+ /*
+ * Bug in Safari. The web view segment faults in some circumstances
+ * when the text changes during the location changing callback. The
+ * fix is to defer the work until the callback is done.
+ */
+ if (changingLocation) {
+ this.html = html;
+ } else {
+ _setText(html);
+ }
+ return true;
+}
+
+void _setText(String html) {
+ NSString string = NSString.stringWith(html);
+ NSString URLString = NSString.stringWith(URI_FROMMEMORY);
+ NSURL URL = NSURL.URLWithString(URLString);
+ WebFrame mainFrame = webView.mainFrame();
+ mainFrame.loadHTMLString(string, URL);
+}
+
+public boolean setUrl(String url) {
+ html = null;
+
+ if (url.indexOf('/') == 0) {
+ url = PROTOCOL_FILE + url;
+ } else if (url.indexOf(':') == -1) {
+ url = PROTOCOL_HTTP + url;
+ }
+
+ NSString str = NSString.stringWith(url);
+ NSString unescapedStr = NSString.stringWith("%#"); //$NON-NLS-1$
+ int /*long*/ ptr = OS.CFURLCreateStringByAddingPercentEscapes(0, str.id, unescapedStr.id, 0, OS.kCFStringEncodingUTF8);
+ NSString escapedString = new NSString(ptr);
+ NSURL inURL = NSURL.URLWithString(escapedString);
+ OS.CFRelease(ptr);
+ NSURLRequest request = NSURLRequest.requestWithURL(inURL);
+ WebFrame mainFrame = webView.mainFrame();
+ mainFrame.loadRequest(request);
+ return true;
+}
+
+public void stop() {
+ html = null;
+ webView.stopLoading(null);
+}
+
+/* WebFrameLoadDelegate */
+
+void webView_didChangeLocationWithinPageForFrame(int /*long*/ sender, int /*long*/ frameID) {
+ WebFrame frame = new WebFrame(frameID);
+ WebDataSource dataSource = frame.dataSource();
+ NSURLRequest request = dataSource.request();
+ NSURL url = request.URL();
+ NSString s = url.absoluteString();
+ int length = (int)/*64*/s.length();
+ if (length == 0) return;
+ String url2 = s.getString();
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ final Display display = browser.getDisplay();
+ boolean top = frameID == webView.mainFrame().id;
+ if (top) {
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = display;
+ statusText.widget = browser;
+ statusText.text = url2;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ }
+
+ LocationEvent location = new LocationEvent(browser);
+ location.display = display;
+ location.widget = browser;
+ location.location = url2;
+ location.top = top;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changed(location);
+ }
+}
+
+void webView_didFailProvisionalLoadWithError_forFrame(int /*long*/ sender, int /*long*/ error, int /*long*/ frame) {
+ if (frame == webView.mainFrame().id) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. However, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ identifier = 0;
+ }
+
+ NSError nserror = new NSError(error);
+ int /*long*/ errorCode = nserror.code();
+ if (errorCode <= OS.NSURLErrorBadURL) {
+ NSString description = nserror.localizedDescription();
+ if (description != null) {
+ String descriptionString = description.getString();
+ String urlString = null;
+ NSDictionary info = nserror.userInfo();
+ if (info != null) {
+ NSString key = new NSString(OS.NSErrorFailingURLStringKey());
+ id id = info.valueForKey(key);
+ if (id != null) {
+ NSString url = new NSString(id);
+ urlString = url.getString();
+ }
+ }
+ String message = urlString != null ? urlString + "\n\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$
+ message += Compatibility.getMessage ("SWT_Page_Load_Failed", new Object[] {descriptionString}); //$NON-NLS-1$
+ MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_ERROR);
+ messageBox.setMessage(message);
+ messageBox.open();
+ }
+ }
+}
+
+void webView_didFinishLoadForFrame(int /*long*/ sender, int /*long*/ frameID) {
+ hookDOMMouseListeners(frameID);
+ if (frameID == webView.mainFrame().id) {
+ hookDOMKeyListeners(frameID);
+
+ final Display display = browser.getDisplay();
+ /*
+ * To be consistent with other platforms a title event should be fired when a
+ * page has completed loading. A page with a <title> tag will do this
+ * automatically when the didReceiveTitle callback is received. However a page
+ * without a <title> tag will not do this by default, so fire the event
+ * here with the page's url as the title.
+ */
+ WebFrame frame = new WebFrame(frameID);
+ WebDataSource dataSource = frame.dataSource();
+ if (dataSource != null) {
+ NSString title = dataSource.pageTitle();
+ if (title == null) { /* page has no title */
+ final TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = display;
+ newEvent.widget = browser;
+ newEvent.title = url;
+ for (int i = 0; i < titleListeners.length; i++) {
+ final TitleListener listener = titleListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The workaround is to invoke Display.asyncExec()
+ * so that the Browser does not crash if this is attempted.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed()) {
+ listener.changed(newEvent);
+ }
+ }
+ }
+ );
+ }
+ }
+ }
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = MAX_PROGRESS;
+ progress.total = MAX_PROGRESS;
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The ProgressBar widget currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncExec() so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed()) {
+ listener.completed(progress);
+ }
+ }
+ }
+ );
+ }
+
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. However, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ identifier = 0;
+ }
+}
+
+void hookDOMKeyListeners(int /*long*/ frameID) {
+ WebFrame frame = new WebFrame(frameID);
+ DOMDocument document = frame.DOMDocument();
+ if (document == null) return;
+
+ NSString type = NSString.stringWith(DOMEVENT_KEYDOWN);
+ document.addEventListener(type, delegate, false);
+
+ type = NSString.stringWith(DOMEVENT_KEYUP);
+ document.addEventListener(type, delegate, false);
+}
+
+void hookDOMMouseListeners(int /*long*/ frameID) {
+ WebFrame frame = new WebFrame(frameID);
+ DOMDocument document = frame.DOMDocument();
+ if (document == null) return;
+
+ NSString type = NSString.stringWith(DOMEVENT_MOUSEDOWN);
+ document.addEventListener(type, delegate, false);
+
+ type = NSString.stringWith(DOMEVENT_MOUSEUP);
+ document.addEventListener(type, delegate, false);
+
+ type = NSString.stringWith(DOMEVENT_MOUSEMOVE);
+ document.addEventListener(type, delegate, false);
+
+ type = NSString.stringWith(DOMEVENT_MOUSEWHEEL);
+ document.addEventListener(type, delegate, false);
+}
+
+void webView_didReceiveTitle_forFrame(int /*long*/ sender, int /*long*/ titleID, int /*long*/ frameID) {
+ if (frameID == webView.mainFrame().id) {
+ NSString title = new NSString(titleID);
+ String newTitle = title.getString();
+ TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.title = newTitle;
+ for (int i = 0; i < titleListeners.length; i++) {
+ titleListeners[i].changed(newEvent);
+ }
+ }
+}
+
+void webView_didStartProvisionalLoadForFrame(int /*long*/ sender, int /*long*/ frameID) {
+ /*
+ * This code is intentionally commented. WebFrameLoadDelegate:didStartProvisionalLoadForFrame is
+ * called before WebResourceLoadDelegate:willSendRequest and
+ * WebFrameLoadDelegate:didCommitLoadForFrame. The resource count is reset when didCommitLoadForFrame
+ * is received for the top frame.
+ */
+// if (frameID == webView.mainFrame().id) {
+// /* reset resource status variables */
+// resourceCount= 0;
+// }
+}
+
+void webView_didCommitLoadForFrame(int /*long*/ sender, int /*long*/ frameID) {
+ WebFrame frame = new WebFrame(frameID);
+ WebDataSource dataSource = frame.dataSource();
+ NSURLRequest request = dataSource.request();
+ NSURL url = request.URL();
+ NSString s = url.absoluteString();
+ int length = (int)/*64*/s.length();
+ if (length == 0) return;
+ String url2 = s.getString();
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ final Display display = browser.getDisplay();
+ boolean top = frameID == webView.mainFrame().id;
+ if (top) {
+ /* reset resource status variables */
+ resourceCount = 0;
+ this.url = url2;
+
+ /* re-install registered functions */
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ BrowserFunction function = (BrowserFunction)elements.nextElement ();
+ execute (function.functionString);
+ }
+
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = 1;
+ progress.total = MAX_PROGRESS;
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The widget ProgressBar currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncexec so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed())
+ listener.changed(progress);
+ }
+ }
+ );
+ }
+
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = display;
+ statusText.widget = browser;
+ statusText.text = url2;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ }
+ LocationEvent location = new LocationEvent(browser);
+ location.display = display;
+ location.widget = browser;
+ location.location = url2;
+ location.top = top;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changed(location);
+ }
+}
+
+void webView_windowScriptObjectAvailable (int /*long*/ webView, int /*long*/ windowScriptObject) {
+ NSObject scriptObject = new NSObject (windowScriptObject);
+ NSString key = NSString.stringWith ("external"); //$NON-NLS-1$
+ scriptObject.setValue (delegate, key);
+}
+
+/* WebResourceLoadDelegate */
+
+void webView_resource_didFinishLoadingFromDataSource(int /*long*/ sender, int /*long*/ identifier, int /*long*/ dataSource) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. However, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ // this code is intentionally commented
+ //if (this.identifier == identifier) this.identifier = 0;
+}
+
+void webView_resource_didFailLoadingWithError_fromDataSource(int /*long*/ sender, int /*long*/ identifier, int /*long*/ error, int /*long*/ dataSource) {
+ /*
+ * Feature on Safari. The identifier is used here as a marker for the events
+ * related to the top frame and the URL changes related to that top frame as
+ * they should appear on the location bar of a browser. It is expected to reset
+ * the identifier to 0 when the event didFinishLoadingFromDataSource related to
+ * the identifierForInitialRequest event is received. However, Safari fires
+ * the didFinishLoadingFromDataSource event before the entire content of the
+ * top frame is loaded. It is possible to receive multiple willSendRequest
+ * events in this interval, causing the Browser widget to send unwanted
+ * Location.changing events. For this reason, the identifier is reset to 0
+ * when the top frame has either finished loading (didFinishLoadForFrame
+ * event) or failed (didFailProvisionalLoadWithError).
+ */
+ // this code is intentionally commented
+ //if (this.identifier == identifier) this.identifier = 0;
+}
+
+void webView_resource_didReceiveAuthenticationChallenge_fromDataSource (int /*long*/ sender, int /*long*/ identifier, int /*long*/ challenge, int /*long*/ dataSource) {
+ NSURLAuthenticationChallenge nsChallenge = new NSURLAuthenticationChallenge (challenge);
+
+ /*
+ * Do not invoke the listeners if this challenge has been failed too many
+ * times because a listener is likely giving incorrect credentials repeatedly
+ * and will do so indefinitely.
+ */
+ if (nsChallenge.previousFailureCount () < 3) {
+ for (int i = 0; i < authenticationListeners.length; i++) {
+ AuthenticationEvent event = new AuthenticationEvent (browser);
+ event.location = lastNavigateURL;
+ authenticationListeners[i].authenticate (event);
+ if (!event.doit) {
+ id challengeSender = nsChallenge.sender ();
+ OS.objc_msgSend (challengeSender.id, OS.sel_cancelAuthenticationChallenge_, challenge);
+ return;
+ }
+ if (event.user != null && event.password != null) {
+ id challengeSender = nsChallenge.sender ();
+ NSString user = NSString.stringWith (event.user);
+ NSString password = NSString.stringWith (event.password);
+ NSURLCredential credential = NSURLCredential.credentialWithUser (user, password, OS.NSURLCredentialPersistenceForSession);
+ OS.objc_msgSend (challengeSender.id, OS.sel_useCredential_forAuthenticationChallenge_, credential.id, challenge);
+ return;
+ }
+ }
+ }
+
+ /* no listener handled the challenge, so try to invoke the native panel */
+ int /*long*/ cls = OS.class_WebPanelAuthenticationHandler;
+ if (cls != 0) {
+ int /*long*/ method = OS.class_getClassMethod (cls, OS.sel_sharedHandler);
+ if (method != 0) {
+ int /*long*/ handler = OS.objc_msgSend (cls, OS.sel_sharedHandler);
+ if (handler != 0) {
+ OS.objc_msgSend (handler, OS.sel_startAuthentication, challenge, webView.window ().id);
+ return;
+ }
+ }
+ }
+
+ /* the native panel was not available, so show a custom dialog */
+ String[] userReturn = new String[1], passwordReturn = new String[1];
+ NSURLCredential proposedCredential = nsChallenge.proposedCredential ();
+ if (proposedCredential != null) {
+ userReturn[0] = proposedCredential.user ().getString ();
+ if (proposedCredential.hasPassword ()) {
+ passwordReturn[0] = proposedCredential.password ().getString ();
+ }
+ }
+ NSURLProtectionSpace space = nsChallenge.protectionSpace ();
+ String host = space.host ().getString () + ':' + space.port ();
+ String realm = space.realm ().getString ();
+ boolean result = showAuthenticationDialog (userReturn, passwordReturn, host, realm);
+ if (!result) {
+ id challengeSender = nsChallenge.sender ();
+ OS.objc_msgSend (challengeSender.id, OS.sel_cancelAuthenticationChallenge_, challenge);
+ return;
+ }
+ id challengeSender = nsChallenge.sender ();
+ NSString user = NSString.stringWith (userReturn[0]);
+ NSString password = NSString.stringWith (passwordReturn[0]);
+ NSURLCredential credential = NSURLCredential.credentialWithUser (user, password, OS.NSURLCredentialPersistenceForSession);
+ OS.objc_msgSend (challengeSender.id, OS.sel_useCredential_forAuthenticationChallenge_, credential.id, challenge);
+}
+
+boolean showAuthenticationDialog (final String[] user, final String[] password, String host, String realm) {
+ final Shell shell = new Shell (browser.getShell ());
+ shell.setLayout (new GridLayout ());
+ String title = SWT.getMessage ("SWT_Authentication_Required"); //$NON-NLS-1$
+ shell.setText (title);
+ Label label = new Label (shell, SWT.WRAP);
+ label.setText (Compatibility.getMessage ("SWT_Enter_Username_and_Password", new String[] {realm, host})); //$NON-NLS-1$
+
+ GridData data = new GridData ();
+ Monitor monitor = browser.getMonitor ();
+ int maxWidth = monitor.getBounds ().width * 2 / 3;
+ int width = label.computeSize (SWT.DEFAULT, SWT.DEFAULT).x;
+ data.widthHint = Math.min (width, maxWidth);
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ label.setLayoutData (data);
+
+ Label userLabel = new Label (shell, SWT.NONE);
+ userLabel.setText (SWT.getMessage ("SWT_Username")); //$NON-NLS-1$
+
+ final Text userText = new Text (shell, SWT.BORDER);
+ if (user[0] != null) userText.setText (user[0]);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ userText.setLayoutData (data);
+
+ Label passwordLabel = new Label (shell, SWT.NONE);
+ passwordLabel.setText (SWT.getMessage ("SWT_Password")); //$NON-NLS-1$
+
+ final Text passwordText = new Text (shell, SWT.PASSWORD | SWT.BORDER);
+ if (password[0] != null) passwordText.setText (password[0]);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.FILL;
+ data.grabExcessHorizontalSpace = true;
+ passwordText.setLayoutData (data);
+
+ final boolean[] result = new boolean[1];
+ final Button[] buttons = new Button[2];
+ Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+ user[0] = userText.getText();
+ password[0] = passwordText.getText();
+ result[0] = event.widget == buttons[1];
+ shell.close();
+ }
+ };
+
+ Composite composite = new Composite (shell, SWT.NONE);
+ data = new GridData ();
+ data.horizontalAlignment = GridData.END;
+ composite.setLayoutData (data);
+ composite.setLayout (new GridLayout (2, true));
+ buttons[0] = new Button (composite, SWT.PUSH);
+ buttons[0].setText (SWT.getMessage("SWT_Cancel")); //$NON-NLS-1$
+ buttons[0].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
+ buttons[0].addListener (SWT.Selection, listener);
+ buttons[1] = new Button (composite, SWT.PUSH);
+ buttons[1].setText (SWT.getMessage("SWT_OK")); //$NON-NLS-1$
+ buttons[1].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
+ buttons[1].addListener (SWT.Selection, listener);
+
+ shell.setDefaultButton (buttons[1]);
+ shell.pack ();
+ shell.open ();
+ Display display = browser.getDisplay ();
+ while (!shell.isDisposed ()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+
+ return result[0];
+}
+
+int /*long*/ webView_identifierForInitialRequest_fromDataSource(int /*long*/ sender, int /*long*/ request, int /*long*/ dataSourceID) {
+ final Display display = browser.getDisplay();
+ final ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = resourceCount;
+ progress.total = Math.max(resourceCount, MAX_PROGRESS);
+ for (int i = 0; i < progressListeners.length; i++) {
+ final ProgressListener listener = progressListeners[i];
+ /*
+ * Note on WebKit. Running the event loop from a Browser
+ * delegate callback breaks the WebKit (stop loading or
+ * crash). The widget ProgressBar currently touches the
+ * event loop every time the method setSelection is called.
+ * The workaround is to invoke Display.asyncexec so that
+ * the Browser does not crash when the user updates the
+ * selection of the ProgressBar.
+ */
+ display.asyncExec(
+ new Runnable() {
+ public void run() {
+ if (!display.isDisposed() && !browser.isDisposed())
+ listener.changed(progress);
+ }
+ }
+ );
+ }
+
+ NSNumber identifier = NSNumber.numberWithInt(resourceCount++);
+ if (this.identifier == 0) {
+ WebDataSource dataSource = new WebDataSource(dataSourceID);
+ WebFrame frame = dataSource.webFrame();
+ if (frame.id == webView.mainFrame().id) this.identifier = identifier.id;
+ }
+ return identifier.id;
+
+}
+
+int /*long*/ webView_resource_willSendRequest_redirectResponse_fromDataSource(int /*long*/ sender, int /*long*/ identifier, int /*long*/ request, int /*long*/ redirectResponse, int /*long*/ dataSource) {
+ NSURLRequest nsRequest = new NSURLRequest (request);
+ NSURL url = nsRequest.URL ();
+ if (url.isFileURL ()) {
+ NSMutableURLRequest newRequest = new NSMutableURLRequest (nsRequest.mutableCopy ());
+ newRequest.autorelease ();
+ newRequest.setCachePolicy (OS.NSURLRequestReloadIgnoringLocalCacheData);
+ return newRequest.id;
+ }
+ return request;
+}
+
+/* UIDelegate */
+
+int /*long*/ webView_createWebViewWithRequest(int /*long*/ sender, int /*long*/ request) {
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.required = true;
+ if (openWindowListeners != null) {
+ for (int i = 0; i < openWindowListeners.length; i++) {
+ openWindowListeners[i].open(newEvent);
+ }
+ }
+ WebView result = null;
+ Browser browser = null;
+ if (newEvent.browser != null && newEvent.browser.webBrowser instanceof Safari) {
+ browser = newEvent.browser;
+ }
+ if (browser != null && !browser.isDisposed()) {
+ result = ((Safari)browser.webBrowser).webView;
+ if (request != 0) {
+ WebFrame mainFrame = result.mainFrame();
+ mainFrame.loadRequest(new NSURLRequest(request));
+ }
+ }
+ return result != null ? result.id : 0;
+}
+
+void webViewShow(int /*long*/ sender) {
+ /*
+ * Feature on WebKit. The Safari WebKit expects the application
+ * to create a new Window using the Objective C Cocoa API in response
+ * to UIDelegate.createWebViewWithRequest. The application is then
+ * expected to use Objective C Cocoa API to make this window visible
+ * when receiving the UIDelegate.webViewShow message. For some reason,
+ * a window created with the Carbon API hosting the new browser instance
+ * does not redraw until it has been resized. The fix is to increase the
+ * size of the Shell and restore it to its initial size.
+ */
+ Shell parent = browser.getShell();
+ Point pt = parent.getSize();
+ parent.setSize(pt.x+1, pt.y);
+ parent.setSize(pt.x, pt.y);
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ if (location != null) newEvent.location = location;
+ if (size != null) newEvent.size = size;
+ /*
+ * Feature in Safari. Safari's tool bar contains
+ * the address bar. The address bar is displayed
+ * if the tool bar is displayed. There is no separate
+ * notification for the address bar.
+ *
+ * Feature of OSX. The menu bar is always displayed.
+ * There is no notification to hide the menu bar.
+ */
+ newEvent.addressBar = toolBar;
+ newEvent.menuBar = true;
+ newEvent.statusBar = statusBar;
+ newEvent.toolBar = toolBar;
+ for (int i = 0; i < visibilityWindowListeners.length; i++) {
+ visibilityWindowListeners[i].show(newEvent);
+ }
+ location = null;
+ size = null;
+}
+
+void webView_setFrame(int /*long*/ sender, int /*long*/ frame) {
+ NSRect rect = new NSRect();
+ OS.memmove(rect, frame, NSRect.sizeof);
+ /* convert to SWT system coordinates */
+ Rectangle bounds = browser.getDisplay().getBounds();
+ location = new Point((int)rect.x, bounds.height - (int)rect.y - (int)rect.height);
+ size = new Point((int)rect.width, (int)rect.height);
+}
+
+void webViewFocus(int /*long*/ sender) {
+}
+
+void webViewUnfocus(int /*long*/ sender) {
+}
+
+void webView_runJavaScriptAlertPanelWithMessage(int /*long*/ sender, int /*long*/ messageID) {
+ NSString message = new NSString(messageID);
+ String text = message.getString();
+
+ MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_WARNING);
+ messageBox.setText("Javascript"); //$NON-NLS-1$
+ messageBox.setMessage(text);
+ messageBox.open();
+}
+
+int webView_runJavaScriptConfirmPanelWithMessage(int /*long*/ sender, int /*long*/ messageID) {
+ NSString message = new NSString(messageID);
+ String text = message.getString();
+
+ MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.CANCEL | SWT.ICON_QUESTION);
+ messageBox.setText("Javascript"); //$NON-NLS-1$
+ messageBox.setMessage(text);
+ return messageBox.open() == SWT.OK ? 1 : 0;
+}
+
+void webView_runOpenPanelForFileButtonWithResultListener(int /*long*/ sender, int /*long*/ resultListenerID) {
+ FileDialog dialog = new FileDialog(browser.getShell(), SWT.NONE);
+ String result = dialog.open();
+ WebOpenPanelResultListener resultListener = new WebOpenPanelResultListener(resultListenerID);
+ if (result == null) {
+ resultListener.cancel();
+ return;
+ }
+ resultListener.chooseFilename(NSString.stringWith(result));
+}
+
+void webViewClose(int /*long*/ sender) {
+ Shell parent = browser.getShell();
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ for (int i = 0; i < closeWindowListeners.length; i++) {
+ closeWindowListeners[i].close(newEvent);
+ }
+ browser.dispose();
+ if (parent.isDisposed()) return;
+ /*
+ * Feature on WebKit. The Safari WebKit expects the application
+ * to create a new Window using the Objective C Cocoa API in response
+ * to UIDelegate.createWebViewWithRequest. The application is then
+ * expected to use Objective C Cocoa API to make this window visible
+ * when receiving the UIDelegate.webViewShow message. For some reason,
+ * a window created with the Carbon API hosting the new browser instance
+ * does not redraw until it has been resized. The fix is to increase the
+ * size of the Shell and restore it to its initial size.
+ */
+ Point pt = parent.getSize();
+ parent.setSize(pt.x+1, pt.y);
+ parent.setSize(pt.x, pt.y);
+}
+
+int /*long*/ webView_contextMenuItemsForElement_defaultMenuItems(int /*long*/ sender, int /*long*/ element, int /*long*/ defaultMenuItems) {
+ Point pt = browser.getDisplay().getCursorLocation();
+ Event event = new Event();
+ event.x = pt.x;
+ event.y = pt.y;
+ browser.notifyListeners(SWT.MenuDetect, event);
+ Menu menu = browser.getMenu();
+ if (!event.doit) return 0;
+ if (menu != null && !menu.isDisposed()) {
+ if (event.x != pt.x || event.y != pt.y) {
+ menu.setLocation(event.x, event.y);
+ }
+ menu.setVisible(true);
+ return 0;
+ }
+ return defaultMenuItems;
+}
+
+void webView_setStatusBarVisible(int /*long*/ sender, boolean visible) {
+ /* Note. Webkit only emits the notification when the status bar should be hidden. */
+ statusBar = visible;
+}
+
+void webView_setStatusText(int /*long*/ sender, int /*long*/ textID) {
+ NSString text = new NSString(textID);
+ int length = (int)/*64*/text.length();
+ if (length == 0) return;
+
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = text.getString();
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+}
+
+void webView_setResizable(int /*long*/ sender, boolean visible) {
+}
+
+void webView_setToolbarsVisible(int /*long*/ sender, boolean visible) {
+ /* Note. Webkit only emits the notification when the tool bar should be hidden. */
+ toolBar = visible;
+}
+
+void webView_mouseDidMoveOverElement_modifierFlags (int /*long*/ sender, int /*long*/ elementInformationID, int /*long*/ modifierFlags) {
+ if (elementInformationID == 0) return;
+
+ NSString key = NSString.stringWith(WebElementLinkURLKey);
+ NSDictionary elementInformation = new NSDictionary(elementInformationID);
+ id value = elementInformation.valueForKey(key);
+ if (value == null) {
+ /* not currently over a link */
+ if (lastHoveredLinkURL == null) return;
+ lastHoveredLinkURL = null;
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = ""; //$NON-NLS-1$
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+ return;
+ }
+
+ NSString url = new NSURL(value.id).absoluteString();
+ int length = (int)/*64*/url.length();
+ String urlString;
+ if (length == 0) {
+ urlString = ""; //$NON-NLS-1$
+ } else {
+ urlString = url.getString();
+ }
+ if (urlString.equals(lastHoveredLinkURL)) return;
+
+ lastHoveredLinkURL = urlString;
+ StatusTextEvent statusText = new StatusTextEvent(browser);
+ statusText.display = browser.getDisplay();
+ statusText.widget = browser;
+ statusText.text = urlString;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(statusText);
+ }
+}
+
+void webView_printFrameView (int /*long*/ sender, int /*long*/ frameViewID) {
+ WebFrameView view = new WebFrameView(frameViewID);
+ boolean viewPrint = view.documentViewShouldHandlePrint();
+ if (viewPrint) {
+ view.printDocumentView();
+ return;
+ }
+ NSPrintInfo info = NSPrintInfo.sharedPrintInfo();
+ NSPrintOperation operation = view.printOperationWithPrintInfo(info);
+ if (operation != null) operation.runOperation();
+}
+
+/* PolicyDelegate */
+
+void webView_decidePolicyForMIMEType_request_frame_decisionListener(int /*long*/ sender, int /*long*/ type, int /*long*/ request, int /*long*/ frame, int /*long*/ listenerID) {
+ boolean canShow = WebView.canShowMIMEType(new NSString(type));
+ WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
+ if (canShow) {
+ listener.use();
+ } else {
+ listener.download();
+ }
+}
+
+void webView_decidePolicyForNavigationAction_request_frame_decisionListener(int /*long*/ sender, int /*long*/ actionInformation, int /*long*/ request, int /*long*/ frame, int /*long*/ listenerID) {
+ NSURL url = new NSURLRequest(request).URL();
+ WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
+ if (url == null) {
+ /* indicates that a URL with an invalid format was specified */
+ listener.ignore();
+ return;
+ }
+ NSString s = url.absoluteString();
+ String url2 = s.getString();
+ /*
+ * If the URI indicates that the page is being rendered from memory
+ * (via setText()) then set it to about:blank to be consistent with IE.
+ */
+ if (url2.equals (URI_FROMMEMORY)) url2 = ABOUT_BLANK;
+
+ LocationEvent newEvent = new LocationEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.location = url2;
+ newEvent.doit = true;
+ if (locationListeners != null) {
+ changingLocation = true;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changing(newEvent);
+ }
+ changingLocation = false;
+ }
+ if (newEvent.doit) {
+ if (jsEnabledChanged) {
+ jsEnabledChanged = false;
+ if (preferences == null) {
+ preferences = (WebPreferences)new WebPreferences ().alloc ().init ();
+ webView.setPreferences (preferences);
+ }
+ preferences.setJavaScriptEnabled (jsEnabled);
+ }
+ listener.use();
+ lastNavigateURL = url2;
+ } else {
+ listener.ignore();
+ }
+ if (html != null && !browser.isDisposed()) {
+ String html = this.html;
+ this.html = null;
+ _setText(html);
+ }
+}
+
+void webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(int /*long*/ sender, int /*long*/ actionInformation, int /*long*/ request, int /*long*/ frameName, int /*long*/ listenerID) {
+ WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
+ listener.use();
+}
+
+void webView_unableToImplementPolicyWithError_frame(int /*long*/ sender, int /*long*/ error, int /*long*/ frame) {
+}
+
+/* WebDownload */
+
+void download_decideDestinationWithSuggestedFilename(int /*long*/ downloadId, int /*long*/ filename) {
+ NSString string = new NSString(filename);
+ String name = string.getString();
+ FileDialog dialog = new FileDialog(browser.getShell(), SWT.SAVE);
+ dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$
+ dialog.setFileName(name);
+ String path = dialog.open();
+ NSURLDownload download = new NSURLDownload(downloadId);
+ if (path == null) {
+ /* cancel pressed */
+ download.cancel();
+ return;
+ }
+ download.setDestination(NSString.stringWith(path), true);
+}
+
+/* DOMEventListener */
+
+void handleEvent(int /*long*/ evtId) {
+ NSString string = new NSString(OS.objc_msgSend(evtId, OS.sel_type));
+ String type = string.getString();
+
+ if (DOMEVENT_KEYDOWN.equals(type) || DOMEVENT_KEYUP.equals(type)) {
+ DOMKeyboardEvent event = new DOMKeyboardEvent(evtId);
+
+ boolean ctrl = event.ctrlKey();
+ boolean shift = event.shiftKey();
+ boolean alt = event.altKey();
+ boolean meta = event.metaKey();
+ int keyCode = event.keyCode();
+ int charCode = event.charCode();
+
+ Event keyEvent = new Event();
+ keyEvent.widget = browser;
+ int eventType = DOMEVENT_KEYDOWN.equals(type) ? SWT.KeyDown : SWT.KeyUp;
+ keyEvent.type = eventType;
+ int translatedKey = translateKey (keyCode);
+ keyEvent.keyCode = translatedKey;
+ keyEvent.character = (char)charCode;
+ int stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ keyEvent.stateMask = stateMask;
+ browser.notifyListeners(keyEvent.type, keyEvent);
+ if (!keyEvent.doit) {
+ event.preventDefault();
+ } else {
+ if (eventType == SWT.KeyDown && stateMask == SWT.COMMAND) {
+ if (translatedKey == 'v') {
+ webView.paste (webView);
+ } else if (translatedKey == 'c') {
+ webView.copy (webView);
+ } else if (translatedKey == 'x') {
+ webView.cut (webView);
+ }
+ }
+ }
+ return;
+ }
+
+ if (DOMEVENT_MOUSEWHEEL.equals(type)) {
+ DOMWheelEvent event = new DOMWheelEvent(evtId);
+ int clientX = event.clientX();
+ int clientY = event.clientY();
+ int delta = event.wheelDelta();
+ boolean ctrl = event.ctrlKey();
+ boolean shift = event.shiftKey();
+ boolean alt = event.altKey();
+ boolean meta = event.metaKey();
+ Event mouseEvent = new Event();
+ mouseEvent.type = SWT.MouseWheel;
+ mouseEvent.widget = browser;
+ mouseEvent.x = clientX; mouseEvent.y = clientY;
+ mouseEvent.count = delta / 120;
+ mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ browser.notifyListeners (mouseEvent.type, mouseEvent);
+ return;
+ }
+
+ /* mouse event */
+
+ DOMMouseEvent event = new DOMMouseEvent(evtId);
+
+ int clientX = event.clientX();
+ int clientY = event.clientY();
+ int detail = event.detail();
+ int button = event.button();
+ boolean ctrl = event.ctrlKey();
+ boolean shift = event.shiftKey();
+ boolean alt = event.altKey();
+ boolean meta = event.metaKey();
+
+ Event mouseEvent = new Event ();
+ mouseEvent.widget = browser;
+ mouseEvent.x = clientX; mouseEvent.y = clientY;
+ mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ if (DOMEVENT_MOUSEDOWN.equals (type)) {
+ mouseEvent.type = SWT.MouseDown;
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ } else if (DOMEVENT_MOUSEUP.equals (type)) {
+ mouseEvent.type = SWT.MouseUp;
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ switch (mouseEvent.button) {
+ case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
+ case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
+ case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
+ case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
+ case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
+ }
+ } else if (DOMEVENT_MOUSEMOVE.equals (type)) {
+ /*
+ * Bug in Safari. Spurious and redundant mousemove events are received in
+ * various contexts, including following every MouseUp. The workaround is
+ * to not fire MouseMove events whose x and y values match the last MouseMove
+ */
+ if (mouseEvent.x == lastMouseMoveX && mouseEvent.y == lastMouseMoveY) return;
+ mouseEvent.type = SWT.MouseMove;
+ lastMouseMoveX = mouseEvent.x; lastMouseMoveY = mouseEvent.y;
+ }
+
+ browser.notifyListeners (mouseEvent.type, mouseEvent);
+ if (detail == 2 && DOMEVENT_MOUSEDOWN.equals (type)) {
+ mouseEvent = new Event ();
+ mouseEvent.widget = browser;
+ mouseEvent.x = clientX; mouseEvent.y = clientY;
+ mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
+ mouseEvent.type = SWT.MouseDoubleClick;
+ mouseEvent.button = button + 1;
+ mouseEvent.count = detail;
+ browser.notifyListeners (mouseEvent.type, mouseEvent);
+ }
+}
+
+/* external */
+
+Object convertToJava (int /*long*/ value) {
+ NSObject object = new NSObject (value);
+ int /*long*/ clazz = OS.objc_lookUpClass ("NSString"); //$NON-NLS-1$
+ if (object.isKindOfClass (clazz)) {
+ NSString string = new NSString (value);
+ return string.getString ();
+ }
+ clazz = OS.objc_lookUpClass ("NSNumber"); //$NON-NLS-1$
+ if (object.isKindOfClass (clazz)) {
+ NSNumber number = new NSNumber (value);
+ int /*long*/ ptr = number.objCType ();
+ byte[] type = new byte[1];
+ OS.memmove (type, ptr, 1);
+ if (type[0] == 'c' || type[0] == 'B') {
+ return new Boolean (number.boolValue ());
+ }
+ if ("islqISLQfd".indexOf (type[0]) != -1) { //$NON-NLS-1$
+ return new Double (number.doubleValue ());
+ }
+ }
+ clazz = OS.objc_lookUpClass ("WebScriptObject"); //$NON-NLS-1$
+ if (object.isKindOfClass (clazz)) {
+ WebScriptObject script = new WebScriptObject (value);
+ id id = script.valueForKey (NSString.stringWith ("length")); //$NON-NLS-1$
+ if (id == null) { /* not a JS array */
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ int length = new NSNumber (id).intValue ();
+ Object[] arguments = new Object[length];
+ for (int i = 0; i < length; i++) {
+ id current = script.webScriptValueAtIndex (i);
+ if (current != null) {
+ arguments[i] = convertToJava (current.id);
+ }
+ }
+ return arguments;
+ }
+ clazz = OS.objc_lookUpClass ("WebUndefined"); //$NON-NLS-1$
+ if (object.isKindOfClass (clazz)) {
+ return null;
+ }
+
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ return null;
+}
+
+NSObject convertToJS (Object value) {
+ if (value == null) {
+ return WebUndefined.undefined ();
+ }
+ if (value instanceof String) {
+ return NSString.stringWith ((String)value);
+ }
+ if (value instanceof Boolean) {
+ return NSNumber.numberWithBool (((Boolean)value).booleanValue ());
+ }
+ if (value instanceof Number) {
+ return NSNumber.numberWithDouble (((Number)value).doubleValue ());
+ }
+ if (value instanceof Object[]) {
+ Object[] arrayValue = (Object[]) value;
+ int length = arrayValue.length;
+ if (length > 0) {
+ NSMutableArray array = NSMutableArray.arrayWithCapacity (length);
+ for (int i = 0; i < length; i++) {
+ Object currentObject = arrayValue[i];
+ array.addObject (convertToJS (currentObject));
+ }
+ return array;
+ }
+ }
+ SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
+ return null;
+}
+
+NSObject callJava (int /*long*/ index, int /*long*/ args, int /*long*/ arg1) {
+ Object returnValue = null;
+ NSObject object = new NSObject (index);
+ int /*long*/ clazz = OS.objc_lookUpClass ("NSNumber"); //$NON-NLS-1$
+ if (object.isKindOfClass (clazz)) {
+ NSNumber number = new NSNumber (index);
+ Object key = new Integer (number.intValue ());
+ BrowserFunction function = (BrowserFunction)functions.get (key);
+ if (function != null) {
+ try {
+ Object temp = convertToJava (args);
+ if (temp instanceof Object[]) {
+ Object[] arguments = (Object[])temp;
+ try {
+ returnValue = function.function (arguments);
+ } catch (Exception e) {
+ /* exception during function invocation */
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ /* invalid argument value type */
+ if (function.isEvaluate) {
+ /* notify the evaluate function so that a java exception can be thrown */
+ function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
+ }
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ }
+ try {
+ return convertToJS (returnValue);
+ } catch (SWTException e) {
+ /* invalid return value type */
+ return convertToJS (WebBrowser.CreateErrorString (e.getLocalizedMessage ()));
+ }
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationEvent.java
new file mode 100644
index 0000000000..9feeec1c71
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationEvent.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * An <code>AuthenticationEvent</code> is sent by a {@link Browser}
+ * to {@link AuthenticationListener}'s when the <code>Browser</code>
+ * navigates to a page that requires authentication. This event allows
+ * a client to either supply authentication credentials, cancel the
+ * authentication, or do nothing (which causes an authentication prompter
+ * to be shown to the user).
+ *
+ * @since 3.5
+ */
+public class AuthenticationEvent extends TypedEvent {
+ /** The location that triggered the authentication challenge */
+ public String location;
+
+ /** The user name to authenticate with */
+ public String user;
+
+ /** The password to authenticate with */
+ public String password;
+
+ /**
+ * A flag indicating whether the authentication should proceed.
+ * Setting this field to <code>false</code> will cancel the operation.
+ */
+ public boolean doit = true;
+
+ static final long serialVersionUID = -8322331206780057921L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public AuthenticationEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " name=" + user
+ + " password=" + password
+ + " location=" + location
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationListener.java
new file mode 100644
index 0000000000..4f8d342c33
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/AuthenticationListener.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * an {@link AuthenticationEvent} notification when the {@link Browser}
+ * encounters a page that requires authentication.
+ *
+ * @see Browser#addAuthenticationListener(AuthenticationListener)
+ * @see Browser#removeAuthenticationListener(AuthenticationListener)
+ *
+ * @since 3.5
+ */
+public interface AuthenticationListener extends SWTEventListener {
+
+/**
+ * This method is called when a page is navigated to that requires
+ * authentication.
+ * <p>
+ * Setting both the event's <code>user</code> and <code>password</code>
+ * fields causes these values to be used as credentials for authentication.
+ * Leaving one or both of these fields as <code>null</code> indicates
+ * that credentials are not known, so an authentication prompter should
+ * be shown to the user. Otherwise, setting the event's <code>doit</code>
+ * field to <code>false</code> cancels the authentication challenge, and
+ * the page will not be loaded.
+ * <p>
+ *
+ * <p>The following fields in the <code>AuthenticationEvent</code> apply:
+ * <ul>
+ * <li>(in) widget the <code>Browser</code> that is attempting to show the
+ * page that requires authentication
+ * <li>(in) location the location issuing the authentication challenge
+ * <li>(in/out) doit can be set to <code>false</code> to cancel the
+ * authentication challenge
+ * <li>(out) user the user name to authenticate with
+ * <li>(out) password the password to authenticate with
+ * </ul>
+ *
+ * @param event the <code>AuthenticationEvent</code> that can be used to
+ * either supply authentication credentials, defer credential input to
+ * an authentication prompter, or cancel an authentication challenge.
+ */
+public void authenticate(AuthenticationEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/Browser.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/Browser.java
new file mode 100755
index 0000000000..05fcc056e3
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/Browser.java
@@ -0,0 +1,992 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ * Instances of this class implement the browser user interface
+ * metaphor. It allows the user to visualize and navigate through
+ * HTML documents.
+ * <p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to set a layout on it.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>MOZILLA</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>CloseWindowListener, LocationListener, OpenWindowListener, ProgressListener, StatusTextListener, TitleListener, VisibilityWindowListener</dd>
+ * </dl>
+ * <p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#browser">Browser snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: ControlExample, BrowserExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+
+public class Browser extends Composite {
+ WebBrowser webBrowser;
+ int userStyle;
+
+ static final String PACKAGE_PREFIX = "org.eclipse.swt.browser."; //$NON-NLS-1$
+ static final String NO_INPUT_METHOD = "org.eclipse.swt.internal.gtk.noInputMethod"; //$NON-NLS-1$
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>SWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a widget which will be the parent of the new instance (cannot be null)
+ * @param style the style of widget to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for browser creation</li>
+ * </ul>
+ *
+ * @see Widget#getStyle
+ *
+ * @since 3.0
+ */
+public Browser (Composite parent, int style) {
+ super (checkParent (parent), checkStyle (style));
+ userStyle = style;
+
+ String platform = SWT.getPlatform ();
+ Display display = parent.getDisplay ();
+ if ("gtk".equals (platform)) display.setData (NO_INPUT_METHOD, null); //$NON-NLS-1$
+ String className = null;
+ if ((style & SWT.MOZILLA) != 0) {
+ className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$
+ } else {
+ if ("win32".equals (platform) || "wpf".equals (platform)) { //$NON-NLS-1$ $NON-NLS-2$
+ className = "org.eclipse.swt.browser.IE"; //$NON-NLS-1$
+ } else if ("motif".equals (platform)) { //$NON-NLS-1$
+ className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$
+ } else if ("gtk".equals (platform)) { //$NON-NLS-1$
+ className = "org.eclipse.swt.browser.Mozilla"; //$NON-NLS-1$
+ } else if ("carbon".equals (platform) || "cocoa".equals (platform)) { //$NON-NLS-1$
+ className = "org.eclipse.swt.browser.Safari"; //$NON-NLS-1$
+ } else if ("photon".equals (platform)) { //$NON-NLS-1$
+ className = "org.eclipse.swt.browser.Voyager"; //$NON-NLS-1$
+ } else {
+ dispose ();
+ SWT.error (SWT.ERROR_NO_HANDLES);
+ }
+ }
+
+ try {
+ Class clazz = Class.forName (className);
+ webBrowser = (WebBrowser)clazz.newInstance ();
+ } catch (ClassNotFoundException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InstantiationException e) {
+ }
+ if (webBrowser == null) {
+ dispose ();
+ SWT.error (SWT.ERROR_NO_HANDLES);
+ }
+
+ webBrowser.setBrowser (this);
+ webBrowser.create (parent, style);
+}
+
+static Composite checkParent (Composite parent) {
+ String platform = SWT.getPlatform ();
+ if (!"gtk".equals (platform)) return parent; //$NON-NLS-1$
+
+ /*
+ * Note. Mozilla provides all IM support needed for text input in web pages.
+ * If SWT creates another input method context for the widget it will cause
+ * indeterminate results to happen (hangs and crashes). The fix is to prevent
+ * SWT from creating an input method context for the Browser widget.
+ */
+ if (parent != null && !parent.isDisposed ()) {
+ Display display = parent.getDisplay ();
+ if (display != null) {
+ if (display.getThread () == Thread.currentThread ()) {
+ display.setData (NO_INPUT_METHOD, "true"); //$NON-NLS-1$
+ }
+ }
+ }
+ return parent;
+}
+
+static int checkStyle(int style) {
+ String platform = SWT.getPlatform ();
+ if ((style & SWT.MOZILLA) != 0) {
+ if ("carbon".equals (platform)) return style | SWT.EMBEDDED; //$NON-NLS-1$
+ if ("motif".equals (platform)) return style | SWT.EMBEDDED; //$NON-NLS-1$
+ return style;
+ }
+
+ if ("win32".equals (platform)) { //$NON-NLS-1$
+ /*
+ * For IE on win32 the border is supplied by the embedded browser, so remove
+ * the style so that the parent Composite will not draw a second border.
+ */
+ return style & ~SWT.BORDER;
+ } else if ("motif".equals (platform)) { //$NON-NLS-1$
+ return style | SWT.EMBEDDED;
+ }
+ return style;
+}
+
+protected void checkWidget () {
+ super.checkWidget ();
+}
+
+/**
+ * Clears all session cookies from all current Browser instances.
+ *
+ * @since 3.2
+ */
+public static void clearSessions () {
+ WebBrowser.clearSessions ();
+}
+
+/**
+ * Returns the value of a cookie that is associated with a URL.
+ * Note that cookies are shared amongst all Browser instances.
+ *
+ * @param name the cookie name
+ * @param url the URL that the cookie is associated with
+ * @return the cookie value, or <code>null</code> if no such cookie exists
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the name is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if the url is null</li>
+ * </ul>
+ *
+ * @since 3.5
+ */
+public static String getCookie (String name, String url) {
+ if (name == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (url == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return WebBrowser.GetCookie (name, url);
+}
+
+/**
+ * Sets a cookie on a URL. Note that cookies are shared amongst all Browser instances.
+ *
+ * The <code>value</code> parameter must be a cookie header string that
+ * complies with <a href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</code>.
+ * The value is passed through to the native browser unchanged.
+ * <p>
+ * Example value strings:
+ * <code>foo=bar</code> (basic session cookie)
+ * <code>foo=bar; path=/; domain=.eclipse.org</code> (session cookie)
+ * <code>foo=bar; expires=Thu, 01-Jan-2030 00:00:01 GMT</code> (persistent cookie)
+ * <code>foo=; expires=Thu, 01-Jan-1970 00:00:01 GMT</code> (deletes cookie <code>foo</code>)
+ *
+ * @param value the cookie value
+ * @param url the URL to associate the cookie with
+ * @return <code>true</code> if the cookie was successfully set and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the value is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if the url is null</li>
+ * </ul>
+ *
+ * @since 3.5
+ */
+public static boolean setCookie (String value, String url) {
+ if (value == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (url == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return WebBrowser.SetCookie (value, url);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when authentication is required.
+ * <p>
+ * This notification occurs when a page requiring authentication is
+ * encountered.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.5
+ */
+public void addAuthenticationListener (AuthenticationListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addAuthenticationListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when the window hosting the receiver should be closed.
+ * <p>
+ * This notification occurs when a javascript command such as
+ * <code>window.close</code> gets executed by a <code>Browser</code>.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addCloseWindowListener (CloseWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addCloseWindowListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when the current location has changed or is about to change.
+ * <p>
+ * This notification typically occurs when the application navigates
+ * to a new location with {@link #setUrl(String)} or when the user
+ * activates a hyperlink.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addLocationListener (LocationListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addLocationListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when a new window needs to be created.
+ * <p>
+ * This notification occurs when a javascript command such as
+ * <code>window.open</code> gets executed by a <code>Browser</code>.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addOpenWindowListener (OpenWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addOpenWindowListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when a progress is made during the loading of the current
+ * URL or when the loading of the current URL has been completed.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addProgressListener (ProgressListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addProgressListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when the status text is changed.
+ * <p>
+ * The status text is typically displayed in the status bar of
+ * a browser application.
+ * </p>
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addStatusTextListener (StatusTextListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addStatusTextListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when the title of the current document is available
+ * or has changed.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addTitleListener (TitleListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addTitleListener (listener);
+}
+
+/**
+ * Adds the listener to the collection of listeners who will be
+ * notified when a window hosting the receiver needs to be displayed
+ * or hidden.
+ *
+ * @param listener the listener which should be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void addVisibilityWindowListener (VisibilityWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.addVisibilityWindowListener (listener);
+}
+
+/**
+ * Navigate to the previous session history item.
+ *
+ * @return <code>true</code> if the operation was successful and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #forward
+ *
+ * @since 3.0
+ */
+public boolean back () {
+ checkWidget();
+ return webBrowser.back ();
+}
+
+protected void checkSubclass () {
+ String name = getClass ().getName ();
+ int index = name.lastIndexOf ('.');
+ if (!name.substring (0, index + 1).equals (PACKAGE_PREFIX)) {
+ SWT.error (SWT.ERROR_INVALID_SUBCLASS);
+ }
+}
+
+/**
+ * Executes the specified script.
+ * <p>
+ * Executes a script containing javascript commands in the context of the current document.
+ * If document-defined functions or properties are accessed by the script then this method
+ * should not be invoked until the document has finished loading (<code>ProgressListener.completed()</code>
+ * gives notification of this).
+ *
+ * @param script the script with javascript commands
+ *
+ * @return <code>true</code> if the operation was successful and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the script is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see ProgressListener#completed(ProgressEvent)
+ *
+ * @since 3.1
+ */
+public boolean execute (String script) {
+ checkWidget();
+ if (script == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return webBrowser.execute (script);
+}
+
+/**
+ * Returns the result, if any, of executing the specified script.
+ * <p>
+ * Evaluates a script containing javascript commands in the context of
+ * the current document. If document-defined functions or properties
+ * are accessed by the script then this method should not be invoked
+ * until the document has finished loading (<code>ProgressListener.completed()</code>
+ * gives notification of this).
+ * </p><p>
+ * If the script returns a value with a supported type then a java
+ * representation of the value is returned. The supported
+ * javascript -> java mappings are:
+ * <ul>
+ * <li>javascript null or undefined -> <code>null</code></li>
+ * <li>javascript number -> <code>java.lang.Double</code></li>
+ * <li>javascript string -> <code>java.lang.String</code></li>
+ * <li>javascript boolean -> <code>java.lang.Boolean</code></li>
+ * <li>javascript array whose elements are all of supported types -> <code>java.lang.Object[]</code></li>
+ * </ul>
+ *
+ * An <code>SWTException</code> is thrown if the return value has an
+ * unsupported type, or if evaluating the script causes a javascript
+ * error to be thrown.
+ *
+ * @param script the script with javascript commands
+ *
+ * @return the return value, if any, of executing the script
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the script is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_FAILED_EVALUATE when the script evaluation causes a javascript error to be thrown</li>
+ * <li>ERROR_INVALID_RETURN_VALUE when the script returns a value of unsupported type</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see ProgressListener#completed(ProgressEvent)
+ *
+ * @since 3.5
+ */
+public Object evaluate (String script) throws SWTException {
+ checkWidget();
+ if (script == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return webBrowser.evaluate (script);
+}
+
+/**
+ * Navigate to the next session history item.
+ *
+ * @return <code>true</code> if the operation was successful and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #back
+ *
+ * @since 3.0
+ */
+public boolean forward () {
+ checkWidget();
+ return webBrowser.forward ();
+}
+
+/**
+ * Returns the type of native browser being used by this instance.
+ * Examples: "mozilla", "ie", "safari", "voyager"
+ *
+ * @return the type of the native browser
+ *
+ * @since 3.5
+ */
+public String getBrowserType () {
+ checkWidget();
+ return webBrowser.getBrowserType ();
+}
+
+/**
+ * Returns <code>true</code> if javascript will be allowed to run in pages
+ * subsequently viewed in the receiver, and <code>false</code> otherwise.
+ *
+ * @return the receiver's javascript enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #setJavascriptEnabled
+ *
+ * @since 3.5
+ */
+public boolean getJavascriptEnabled () {
+ checkWidget();
+ return webBrowser.jsEnabled;
+}
+
+public int getStyle () {
+ /*
+ * If SWT.BORDER was specified at creation time then getStyle() should answer
+ * it even though it is removed for IE on win32 in checkStyle().
+ */
+ return super.getStyle () | (userStyle & SWT.BORDER);
+}
+
+/**
+ * Returns a string with HTML that represents the content of the current page.
+ *
+ * @return HTML representing the current page or an empty <code>String</code>
+ * if this is empty
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public String getText () {
+ checkWidget();
+ return webBrowser.getText ();
+}
+
+/**
+ * Returns the current URL.
+ *
+ * @return the current URL or an empty <code>String</code> if there is no current URL
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #setUrl
+ *
+ * @since 3.0
+ */
+public String getUrl () {
+ checkWidget();
+ return webBrowser.getUrl ();
+}
+
+/**
+ * Returns the JavaXPCOM <code>nsIWebBrowser</code> for the receiver, or <code>null</code>
+ * if it is not available. In order for an <code>nsIWebBrowser</code> to be returned all
+ * of the following must be true: <ul>
+ * <li>the receiver's style must be <code>SWT.MOZILLA</code></li>
+ * <li>the classes from JavaXPCOM &gt;= 1.8.1.2 must be resolvable at runtime</li>
+ * <li>the version of the underlying XULRunner must be &gt;= 1.8.1.2</li>
+ * </ul>
+ *
+ * @return the receiver's JavaXPCOM <code>nsIWebBrowser</code> or <code>null</code>
+ *
+ * @since 3.3
+ */
+public Object getWebBrowser () {
+ checkWidget();
+ return webBrowser.getWebBrowser ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver can navigate to the
+ * previous session history item, and <code>false</code> otherwise.
+ *
+ * @return the receiver's back command enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #back
+ */
+public boolean isBackEnabled () {
+ checkWidget();
+ return webBrowser.isBackEnabled ();
+}
+
+public boolean isFocusControl () {
+ checkWidget();
+ if (webBrowser.isFocusControl ()) return true;
+ return super.isFocusControl ();
+}
+
+/**
+ * Returns <code>true</code> if the receiver can navigate to the
+ * next session history item, and <code>false</code> otherwise.
+ *
+ * @return the receiver's forward command enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #forward
+ */
+public boolean isForwardEnabled () {
+ checkWidget();
+ return webBrowser.isForwardEnabled ();
+}
+
+/**
+ * Refresh the current page.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void refresh () {
+ checkWidget();
+ webBrowser.refresh ();
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when authentication is required.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.5
+ */
+public void removeAuthenticationListener (AuthenticationListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeAuthenticationListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the window hosting the receiver should be closed.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeCloseWindowListener (CloseWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeCloseWindowListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the current location is changed or about to be changed.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeLocationListener (LocationListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeLocationListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a new window needs to be created.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeOpenWindowListener (OpenWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeOpenWindowListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a progress is made during the loading of the current
+ * URL or when the loading of the current URL has been completed.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeProgressListener (ProgressListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeProgressListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the status text is changed.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeStatusTextListener (StatusTextListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeStatusTextListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when the title of the current document is available
+ * or has changed.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeTitleListener (TitleListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeTitleListener (listener);
+}
+
+/**
+ * Removes the listener from the collection of listeners who will
+ * be notified when a window hosting the receiver needs to be displayed
+ * or hidden.
+ *
+ * @param listener the listener which should no longer be notified
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void removeVisibilityWindowListener (VisibilityWindowListener listener) {
+ checkWidget();
+ if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ webBrowser.removeVisibilityWindowListener (listener);
+}
+
+/**
+ * Sets whether javascript will be allowed to run in pages subsequently
+ * viewed in the receiver. Note that setting this value does not affect
+ * the running of javascript in the current page.
+ *
+ * @param enabled the receiver's new javascript enabled state
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @since 3.5
+ */
+public void setJavascriptEnabled (boolean enabled) {
+ checkWidget();
+ webBrowser.jsEnabled = enabled;
+ webBrowser.jsEnabledChanged = true;
+}
+
+/**
+ * Renders a string containing HTML. The rendering of the content occurs asynchronously.
+ *
+ * <p>
+ * The html parameter is Unicode encoded since it is a java <code>String</code>.
+ * As a result, the HTML meta tag charset should not be set. The charset is implied
+ * by the <code>String</code> itself.
+ *
+ * @param html the HTML content to be rendered
+ *
+ * @return true if the operation was successful and false otherwise.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the html is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #setUrl
+ *
+ * @since 3.0
+ */
+public boolean setText (String html) {
+ checkWidget();
+ if (html == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return webBrowser.setText (html);
+}
+
+/**
+ * Begins loading a URL. The loading of its content occurs asynchronously.
+ *
+ * @param url the URL to be loaded
+ *
+ * @return true if the operation was successful and false otherwise.
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the url is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @see #getUrl
+ *
+ * @since 3.0
+ */
+public boolean setUrl (String url) {
+ checkWidget();
+ if (url == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return webBrowser.setUrl (url);
+}
+
+/**
+ * Stop any loading and rendering activity.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void stop () {
+ checkWidget();
+ webBrowser.stop ();
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/BrowserFunction.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/BrowserFunction.java
new file mode 100644
index 0000000000..f87aef0d47
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/BrowserFunction.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2008 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 org.eclipse.swt.*;
+
+/**
+ * Instances of this class represent java-side "functions" that
+ * are invokable from javascript. Browser clients define these
+ * functions by subclassing <code>BrowserFunction</code> and
+ * overriding its <code>function(Object[])</code> method. This
+ * method will be invoked whenever javascript running in the
+ * Browser makes a call with the function's name.
+ *
+ * <p>
+ * Application code must explicitly invoke the
+ * <code>BrowserFunction.dispose()</code> method to release the
+ * resources managed by each instance when those instances are no
+ * longer required. Since there is usually a correlation between
+ * the registering of BrowserFunction(s) in a Browser and the
+ * loading of a page in the Browser that is aware of these
+ * functions, the <code>LocationListener.changed()</code> listener
+ * is often a good place to do this.
+ * </p><p>
+ * Note that disposing a Browser automatically disposes all
+ * BrowserFunctions associated with it.
+ * </p>
+ *
+ * @see #dispose()
+ * @see #function(Object[])
+ * @see org.eclipse.swt.browser.LocationListener#changed(LocationEvent)
+ *
+ * @since 3.5
+ */
+public class BrowserFunction {
+ Browser browser;
+ String name;
+ String functionString;
+ int index;
+ boolean isEvaluate;
+
+/**
+ * Constructs a new instance of this class, which will be invokable
+ * by javascript running in the specified Browser.
+ * <p>
+ * You must dispose the BrowserFunction when it is no longer required.
+ * A common place to do this is in a <code>LocationListener.changed()</code>
+ * listener.
+ * </p>
+ * @param browser the browser whose javascript can invoke this function
+ * @param name the name that javascript will use to invoke this function
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the browser is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if the name is null</li>
+ * </ul>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the browser has been disposed</li>
+ * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ *
+ * @see #dispose()
+ * @see org.eclipse.swt.browser.LocationListener#changed(LocationEvent)
+ */
+public BrowserFunction (Browser browser, String name) {
+ this (browser, name, true);
+}
+
+BrowserFunction (Browser browser, String name, boolean create) {
+ super ();
+ if (browser == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (name == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (browser.isDisposed ()) SWT.error (SWT.ERROR_WIDGET_DISPOSED);
+ browser.checkWidget ();
+ this.browser = browser;
+ this.name = name;
+ if (create) browser.webBrowser.createFunction (this);
+}
+
+/**
+ * Disposes of the resources associated with this BrowserFunction.
+ * Applications must dispose of all BrowserFunctions that they create.
+ * </p><p>
+ * Note that disposing a Browser automatically disposes all
+ * BrowserFunctions associated with it.
+ * </p>
+ */
+public void dispose () {
+ dispose (true);
+}
+
+void dispose (boolean remove) {
+ if (index < 0) return;
+ if (remove) browser.webBrowser.destroyFunction (this);
+ browser = null;
+ name = functionString = null;
+ index = -1;
+}
+
+/**
+ * Subclasses should override this method. This method is invoked when
+ * the receiver's function is called from javascript. If all of the
+ * arguments that are passed to the javascript function call are of
+ * supported types then this method is invoked with the argument values
+ * converted as follows:
+ *
+ * javascript null or undefined -> <code>null</code>
+ * javascript number -> <code>java.lang.Double</code>
+ * javascript string -> <code>java.lang.String</code>
+ * javascript boolean -> <code>java.lang.Boolean</code>
+ * javascript array whose elements are all of supported types -> <code>java.lang.Object[]</code>
+ *
+ * If any of the Javascript arguments are of unsupported types then the
+ * function invocation will fail and this method will not be called.
+ *
+ * This method must return a value with one of these supported types to
+ * the javascript caller (note that any subclass of <code>java.lang.Number</code>
+ * will be successfully converted to a javascript number).
+ *
+ * @param arguments the javascript arguments converted to java equivalents
+ * @return the value to return to the javascript caller
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_FUNCTION_DISPOSED when the BrowserFunction has been disposed</li>
+ * </ul>
+ */
+public Object function (Object[] arguments) {
+ if (index < 0) SWT.error (SWT.ERROR_FUNCTION_DISPOSED);
+ browser.checkWidget ();
+ return null;
+}
+
+/**
+ * Returns the Browser whose pages can invoke this BrowserFunction.
+ *
+ * @return the Browser associated with this BrowserFunction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_FUNCTION_DISPOSED when the BrowserFunction has been disposed</li>
+ * </ul>
+ */
+public Browser getBrowser () {
+ if (index < 0) SWT.error (SWT.ERROR_FUNCTION_DISPOSED);
+ browser.checkWidget ();
+ return browser;
+}
+
+/**
+ * Returns the name that javascript can use to invoke this BrowserFunction.
+ *
+ * @return the BrowserFunction's name
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
+ * <li>ERROR_FUNCTION_DISPOSED when the BrowserFunction has been disposed</li>
+ * </ul>
+ */
+public String getName () {
+ if (index < 0) SWT.error (SWT.ERROR_FUNCTION_DISPOSED);
+ browser.checkWidget ();
+ return name;
+}
+
+/**
+ * Returns <code>true</code> if this BrowserFunction has been disposed
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the BrowserFunction.
+ * When a BrowserFunction has been disposed it is an error to
+ * invoke any of its methods.
+ * </p><p>
+ * Note that disposing a Browser automatically disposes all
+ * BrowserFunctions associated with it.
+ * </p>
+ * @return <code>true</code> if this BrowserFunction has been disposed
+ * and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ return index < 0;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/CloseWindowListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/CloseWindowListener.java
new file mode 100644
index 0000000000..b545054e7c
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/CloseWindowListener.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link WindowEvent} notification when a {@link Browser} is
+ * about to be closed and when its host window should be closed
+ * by the application.
+ *
+ * @see Browser#addCloseWindowListener(CloseWindowListener)
+ * @see Browser#removeCloseWindowListener(CloseWindowListener)
+ * @see OpenWindowListener
+ * @see VisibilityWindowListener
+ *
+ * @since 3.0
+ */
+public interface CloseWindowListener extends SWTEventListener {
+
+/**
+ * This method is called when the window hosting a {@link Browser} should be closed.
+ * Application would typically close the {@link org.eclipse.swt.widgets.Shell} that
+ * hosts the <code>Browser</code>. The <code>Browser</code> is disposed after this
+ * notification.
+ *
+ * <p>The following fields in the <code>WindowEvent</code> apply:
+ * <ul>
+ * <li>(in) widget the <code>Browser</code> that is going to be disposed
+ * </ul></p>
+ *
+ * @param event the <code>WindowEvent</code> that specifies the <code>Browser</code>
+ * that is going to be disposed
+ *
+ * @see org.eclipse.swt.widgets.Shell#close()
+ *
+ * @since 3.0
+ */
+public void close(WindowEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationAdapter.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationAdapter.java
new file mode 100644
index 0000000000..1583f43faa
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationAdapter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link LocationListener} interface.
+ * <p>
+ * Classes that wish to deal with {@link LocationEvent}'s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public abstract class LocationAdapter implements LocationListener {
+
+public void changing(LocationEvent event) {
+}
+
+public void changed(LocationEvent event) {
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationEvent.java
new file mode 100644
index 0000000000..0fed868b06
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationEvent.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * A <code>LocationEvent</code> is sent by a {@link Browser} to
+ * {@link LocationListener}'s when the <code>Browser</code>
+ * navigates to a different URL. This notification typically
+ * occurs when the application navigates to a new location with
+ * {@link Browser#setUrl(String)} or when the user activates a
+ * hyperlink.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public class LocationEvent extends TypedEvent {
+ /** current location */
+ public String location;
+
+ /**
+ * A flag indicating whether the location opens in the top frame
+ * or not.
+ */
+ public boolean top;
+
+ /**
+ * A flag indicating whether the location loading should be allowed.
+ * Setting this field to <code>false</code> will cancel the operation.
+ */
+ public boolean doit;
+
+ static final long serialVersionUID = 3906644198244299574L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public LocationEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " location=" + location
+ + " top=" + top
+ + " doit=" + doit
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationListener.java
new file mode 100644
index 0000000000..b34359ba89
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/LocationListener.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link LocationEvent} notification when a {@link Browser}
+ * navigates to a different URL.
+ *
+ * @see Browser#addLocationListener(LocationListener)
+ * @see Browser#removeLocationListener(LocationListener)
+ *
+ * @since 3.0
+ */
+public interface LocationListener extends SWTEventListener {
+
+/**
+ * This method is called when the current location is about to be changed.
+ * <p>
+ *
+ * <p>The following fields in the <code>LocationEvent</code> apply:
+ * <ul>
+ * <li>(in) location the location to be loaded
+ * <li>(in) widget the <code>Browser</code> whose location is changing
+ * <li>(in/out) doit can be set to <code>false</code> to prevent the location
+ * from being loaded
+ * </ul>
+ *
+ * @param event the <code>LocationEvent</code> that specifies the location
+ * to be loaded by a <code>Browser</code>
+ *
+ * @since 3.0
+ */
+public void changing(LocationEvent event);
+
+/**
+ * This method is called when the current location is changed.
+ * <p>
+ *
+ * <p>The following fields in the <code>LocationEvent</code> apply:
+ * <ul>
+ * <li>(in) location the current location
+ * <li>(in) top <code>true</code> if the location opens in the top frame or
+ * <code>false</code> otherwise
+ * <li>(in) widget the <code>Browser</code> whose location has changed
+ * </ul>
+ *
+ * @param event the <code>LocationEvent</code> that specifies the new
+ * location of a <code>Browser</code>
+ *
+ * @since 3.0
+ */
+public void changed(LocationEvent event);
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/OpenWindowListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/OpenWindowListener.java
new file mode 100644
index 0000000000..140f7c3d33
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/OpenWindowListener.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link WindowEvent} notification when a new {@link Browser}
+ * needs to be provided by the application.
+ *
+ * @see Browser#addOpenWindowListener(OpenWindowListener)
+ * @see Browser#removeOpenWindowListener(OpenWindowListener)
+ * @see CloseWindowListener
+ * @see VisibilityWindowListener
+ *
+ * @since 3.0
+ */
+public interface OpenWindowListener extends SWTEventListener {
+
+/**
+ * This method is called when a new window needs to be created.
+ * <p>
+ * A particular <code>Browser</code> can be passed to the event.browser
+ * field to host the content of a new window.
+ * <p>
+ * A standalone system browser is used to host the new window
+ * if the event.required field value is false and if the event.browser
+ * field is left <code>null</code>. The event.required field
+ * is true on platforms that don't support a standalone system browser for
+ * new window requests.
+ * <p>
+ * The navigation is cancelled if the event.required field is set to
+ * true and the event.browser field is left <code>null</code>.
+ * <p>
+ * <p>The following fields in the <code>WindowEvent</code> apply:
+ * <ul>
+ * <li>(in/out) required true if the platform requires the user to provide a
+ * <code>Browser</code> to handle the new window or false otherwise.
+ * <li>(out) browser the new <code>Browser</code> that will host the
+ * content of the new window.
+ * <li>(in) widget the <code>Browser</code> that is requesting to open a
+ * new window
+ * </ul>
+ *
+ * @param event the <code>WindowEvent</code> that needs to be passed a new
+ * <code>Browser</code> to handle the new window request
+ *
+ * @since 3.0
+ */
+public void open(WindowEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressAdapter.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressAdapter.java
new file mode 100644
index 0000000000..98995dbe14
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressAdapter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link ProgressListener} interface.
+ * <p>
+ * Classes that wish to deal with {@link ProgressEvent}'s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public abstract class ProgressAdapter implements ProgressListener {
+
+public void changed(ProgressEvent event) {
+}
+
+public void completed(ProgressEvent event) {
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressEvent.java
new file mode 100644
index 0000000000..204e2edaa6
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressEvent.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * A <code>ProgressEvent</code> is sent by a {@link Browser} to
+ * {@link ProgressListener}'s when a progress is made during the
+ * loading of the current URL or when the loading of the current
+ * URL has been completed.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public class ProgressEvent extends TypedEvent {
+ /** current value */
+ public int current;
+ /** total value */
+ public int total;
+
+ static final long serialVersionUID = 3977018427045393972L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public ProgressEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " current=" + current
+ + " total=" + total
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressListener.java
new file mode 100644
index 0000000000..06fbc40f55
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/ProgressListener.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link ProgressEvent} notification when a {@link Browser}
+ * makes a progress in loading the current URL or when the
+ * current URL has been loaded.
+ *
+ * @see Browser#addProgressListener(ProgressListener)
+ * @see Browser#removeProgressListener(ProgressListener)
+ * @see Browser#getUrl()
+ *
+ * @since 3.0
+ */
+public interface ProgressListener extends SWTEventListener {
+
+/**
+ * This method is called when a progress is made during the loading of the
+ * current location.
+ * <p>
+ *
+ * <p>The following fields in the <code>ProgressEvent</code> apply:
+ * <ul>
+ * <li>(in) current the progress for the location currently being loaded
+ * <li>(in) total the maximum progress for the location currently being loaded
+ * <li>(in) widget the <code>Browser</code> whose current URL is being loaded
+ * </ul>
+ *
+ * @param event the <code>ProgressEvent</code> related to the loading of the
+ * current location of a <code>Browser</code>
+ *
+ * @since 3.0
+ */
+public void changed(ProgressEvent event);
+
+/**
+ * This method is called when the current location has been completely loaded.
+ * <p>
+ *
+ * <p>The following fields in the <code>ProgressEvent</code> apply:
+ * <ul>
+ * <li>(in) widget the <code>Browser</code> whose current URL has been loaded
+ * </ul>
+ *
+ * @param event the <code>ProgressEvent</code> related to the <code>Browser</code>
+ * that has loaded its current URL.
+ *
+ * @since 3.0
+ */
+public void completed(ProgressEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextEvent.java
new file mode 100644
index 0000000000..995d76498b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextEvent.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * A <code>StatusTextEvent</code> is sent by a {@link Browser} to
+ * {@link StatusTextListener}'s when the status text is changed.
+ * The status text is typically displayed in the status bar of
+ * a browser application.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public class StatusTextEvent extends TypedEvent {
+ /** status text */
+ public String text;
+
+ static final long serialVersionUID = 3258407348371600439L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public StatusTextEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " text=" + text
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextListener.java
new file mode 100644
index 0000000000..68e23fbe3c
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/StatusTextListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link StatusTextEvent} notification when the status text for
+ * a {@link Browser} is changed.
+ *
+ * @see Browser#addStatusTextListener(StatusTextListener)
+ * @see Browser#removeStatusTextListener(StatusTextListener)
+ *
+ * @since 3.0
+ */
+public interface StatusTextListener extends SWTEventListener {
+
+/**
+ * This method is called when the status text is changed. The
+ * status text is typically displayed in the status bar of a browser
+ * application.
+ * <p>
+ *
+ * <p>The following fields in the <code>StatusTextEvent</code> apply:
+ * <ul>
+ * <li>(in) text the modified status text
+ * <li>(in) widget the <code>Browser</code> whose status text is changed
+ * </ul>
+ *
+ * @param event the <code>StatusTextEvent</code> that contains the updated
+ * status description of a <code>Browser</code>
+ *
+ * @since 3.0
+ */
+public void changed(StatusTextEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleEvent.java
new file mode 100644
index 0000000000..d2d9eacb23
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleEvent.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+
+/**
+ * A <code>TitleEvent</code> is sent by a {@link Browser} to
+ * {@link TitleListener}'s when the title of the current document
+ * is available or when it is modified.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public class TitleEvent extends TypedEvent {
+ /** the title of the current document */
+ public String title;
+
+ static final long serialVersionUID = 4121132532906340919L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public TitleEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " title=" + title
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleListener.java
new file mode 100644
index 0000000000..a6cbaeb42b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/TitleListener.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2005 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link TitleEvent} notification when the title of the document
+ * displayed in a {@link Browser} is known or has been changed.
+ *
+ * @see Browser#addTitleListener(TitleListener)
+ * @see Browser#removeTitleListener(TitleListener)
+ *
+ * @since 3.0
+ */
+public interface TitleListener extends SWTEventListener {
+
+/**
+ * This method is called when the title of the current document
+ * is available or has changed.
+ * <p>
+ *
+ * <p>The following fields in the <code>TitleEvent</code> apply:
+ * <ul>
+ * <li>(in) title the title of the current document
+ * <li>(in) widget the <code>Browser</code> whose current document's
+ * title is known or modified
+ * </ul>
+ *
+ * @param event the <code>TitleEvent</code> that contains the title
+ * of the document currently displayed in a <code>Browser</code>
+ *
+ * @since 3.0
+ */
+public void changed(TitleEvent event);
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowAdapter.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowAdapter.java
new file mode 100644
index 0000000000..62808fa1c0
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowAdapter.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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;
+
+/**
+ * This adapter class provides default implementations for the
+ * methods described by the {@link VisibilityWindowListener} interface.
+ * <p>
+ * Classes that wish to deal with {@link WindowEvent}'s can
+ * extend this class and override only the methods which they are
+ * interested in.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public abstract class VisibilityWindowAdapter implements VisibilityWindowListener {
+
+public void hide(WindowEvent event) {
+}
+
+public void show(WindowEvent event) {
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowListener.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowListener.java
new file mode 100644
index 0000000000..78833d93ea
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/VisibilityWindowListener.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2007 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 org.eclipse.swt.internal.SWTEventListener;
+
+/**
+ * This listener interface may be implemented in order to receive
+ * a {@link WindowEvent} notification when a window hosting a
+ * {@link Browser} needs to be displayed or hidden.
+ *
+ * @see Browser#addVisibilityWindowListener(VisibilityWindowListener)
+ * @see Browser#removeVisibilityWindowListener(VisibilityWindowListener)
+ * @see OpenWindowListener
+ * @see CloseWindowListener
+ *
+ * @since 3.0
+ */
+public interface VisibilityWindowListener extends SWTEventListener {
+
+/**
+ * This method is called when the window hosting a <code>Browser</code>
+ * is requested to be hidden. Application would typically hide the
+ * {@link org.eclipse.swt.widgets.Shell} that hosts the <code>Browser</code>.
+ * <p>
+ *
+ * <p>The following fields in the <code>WindowEvent</code> apply:
+ * <ul>
+ * <li>(in) widget the <code>Browser</code> that needs to be hidden
+ * </ul>
+ *
+ * @param event the <code>WindowEvent</code> that specifies the
+ * <code>Browser</code> that needs to be hidden
+ *
+ * @see org.eclipse.swt.widgets.Shell#setVisible(boolean)
+ *
+ * @since 3.0
+ */
+public void hide(WindowEvent event);
+
+/**
+ * This method is called when the window hosting a <code>Browser</code>
+ * is requested to be displayed. Application would typically set the
+ * location and the size of the {@link org.eclipse.swt.widgets.Shell}
+ * that hosts the <code>Browser</code>, if a particular location and size
+ * are specified. The application would then open that <code>Shell</code>.
+ * <p>
+ *
+ * <p>The following fields in the <code>WindowEvent</code> apply:
+ * <ul>
+ * <li>(in) widget the <code>Browser</code> to display
+ * <li>(in) location the requested location for the <code>Shell</code>
+ * hosting the browser. It is <code>null</code> if no location is set.
+ * <li>(in) size the requested size for the <code>Browser</code>.
+ * The client area of the <code>Shell</code> hosting the
+ * <code>Browser</code> should be large enough to accommodate that size.
+ * It is <code>null</code> if no size is set.
+ * <li>(in) addressBar <code>true</code> if the <code>Shell</code>
+ * hosting the <code>Browser</code> should display an address bar or
+ * <code>false</code> otherwise
+ * <li>(in) menuBar <code>true</code> if the <code>Shell</code>
+ * hosting the <code>Browser</code> should display a menu bar or
+ * <code>false</code> otherwise
+ * <li>(in) statusBar <code>true</code> if the <code>Shell</code>
+ * hosting the <code>Browser</code> should display a status bar or
+ * <code>false</code> otherwise
+ * <li>(in) toolBar <code>true</code> if the <code>Shell</code>
+ * hosting the <code>Browser</code> should display a tool bar or
+ * <code>false</code> otherwise
+ * </ul>
+ *
+ * @param event the <code>WindowEvent</code> that specifies the
+ * <code>Browser</code> that needs to be displayed
+ *
+ * @see org.eclipse.swt.widgets.Control#setLocation(org.eclipse.swt.graphics.Point)
+ * @see org.eclipse.swt.widgets.Control#setSize(org.eclipse.swt.graphics.Point)
+ * @see org.eclipse.swt.widgets.Shell#open()
+ *
+ * @since 3.0
+ */
+public void show(WindowEvent event);
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java
new file mode 100644
index 0000000000..ea8ef4b38a
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WebBrowser.java
@@ -0,0 +1,598 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.widgets.*;
+
+abstract class WebBrowser {
+ Browser browser;
+ Hashtable functions = new Hashtable ();
+ AuthenticationListener[] authenticationListeners = new AuthenticationListener[0];
+ CloseWindowListener[] closeWindowListeners = new CloseWindowListener[0];
+ LocationListener[] locationListeners = new LocationListener[0];
+ OpenWindowListener[] openWindowListeners = new OpenWindowListener[0];
+ ProgressListener[] progressListeners = new ProgressListener[0];
+ StatusTextListener[] statusTextListeners = new StatusTextListener[0];
+ TitleListener[] titleListeners = new TitleListener[0];
+ VisibilityWindowListener[] visibilityWindowListeners = new VisibilityWindowListener[0];
+ boolean jsEnabled = true;
+ boolean jsEnabledChanged;
+ int nextFunctionIndex = 1;
+ Object evaluateResult;
+
+ static final String ERROR_ID = "org.eclipse.swt.browser.error"; // $NON-NLS-1$
+ static final String EXECUTE_ID = "SWTExecuteTemporaryFunction"; // $NON-NLS-1$
+ static String CookieName, CookieValue, CookieUrl;
+ static boolean CookieResult;
+ static Runnable MozillaClearSessions, NativeClearSessions;
+ static Runnable MozillaGetCookie, NativeGetCookie;
+ static Runnable MozillaSetCookie, NativeSetCookie;
+
+ /* Key Mappings */
+ static final int [][] KeyTable = {
+ /* Keyboard and Mouse Masks */
+ {18, SWT.ALT},
+ {16, SWT.SHIFT},
+ {17, SWT.CONTROL},
+ {224, SWT.COMMAND},
+
+ /* Literal Keys */
+ {65, 'a'},
+ {66, 'b'},
+ {67, 'c'},
+ {68, 'd'},
+ {69, 'e'},
+ {70, 'f'},
+ {71, 'g'},
+ {72, 'h'},
+ {73, 'i'},
+ {74, 'j'},
+ {75, 'k'},
+ {76, 'l'},
+ {77, 'm'},
+ {78, 'n'},
+ {79, 'o'},
+ {80, 'p'},
+ {81, 'q'},
+ {82, 'r'},
+ {83, 's'},
+ {84, 't'},
+ {85, 'u'},
+ {86, 'v'},
+ {87, 'w'},
+ {88, 'x'},
+ {89, 'y'},
+ {90, 'z'},
+ {48, '0'},
+ {49, '1'},
+ {50, '2'},
+ {51, '3'},
+ {52, '4'},
+ {53, '5'},
+ {54, '6'},
+ {55, '7'},
+ {56, '8'},
+ {57, '9'},
+ {32, ' '},
+ {59, ';'},
+ {61, '='},
+ {188, ','},
+ {190, '.'},
+ {191, '/'},
+ {219, '['},
+ {221, ']'},
+ {222, '\''},
+ {192, '`'},
+ {220, '\\'},
+ {108, '|'},
+
+ /* Non-Numeric Keypad Keys */
+ {37, SWT.ARROW_LEFT},
+ {39, SWT.ARROW_RIGHT},
+ {38, SWT.ARROW_UP},
+ {40, SWT.ARROW_DOWN},
+ {45, SWT.INSERT},
+ {36, SWT.HOME},
+ {35, SWT.END},
+ {46, SWT.DEL},
+ {33, SWT.PAGE_UP},
+ {34, SWT.PAGE_DOWN},
+
+ /* Virtual and Ascii Keys */
+ {8, SWT.BS},
+ {13, SWT.CR},
+ {9, SWT.TAB},
+ {27, SWT.ESC},
+ {12, SWT.DEL},
+
+ /* Functions Keys */
+ {112, SWT.F1},
+ {113, SWT.F2},
+ {114, SWT.F3},
+ {115, SWT.F4},
+ {116, SWT.F5},
+ {117, SWT.F6},
+ {118, SWT.F7},
+ {119, SWT.F8},
+ {120, SWT.F9},
+ {121, SWT.F10},
+ {122, SWT.F11},
+ {123, SWT.F12},
+ {124, SWT.F13},
+ {125, SWT.F14},
+ {126, SWT.F15},
+ {127, 0},
+ {128, 0},
+ {129, 0},
+ {130, 0},
+ {131, 0},
+ {132, 0},
+ {133, 0},
+ {134, 0},
+ {135, 0},
+
+ /* Numeric Keypad Keys */
+ {96, SWT.KEYPAD_0},
+ {97, SWT.KEYPAD_1},
+ {98, SWT.KEYPAD_2},
+ {99, SWT.KEYPAD_3},
+ {100, SWT.KEYPAD_4},
+ {101, SWT.KEYPAD_5},
+ {102, SWT.KEYPAD_6},
+ {103, SWT.KEYPAD_7},
+ {104, SWT.KEYPAD_8},
+ {105, SWT.KEYPAD_9},
+ {14, SWT.KEYPAD_CR},
+ {107, SWT.KEYPAD_ADD},
+ {109, SWT.KEYPAD_SUBTRACT},
+ {106, SWT.KEYPAD_MULTIPLY},
+ {111, SWT.KEYPAD_DIVIDE},
+ {110, SWT.KEYPAD_DECIMAL},
+
+ /* Other keys */
+ {20, SWT.CAPS_LOCK},
+ {144, SWT.NUM_LOCK},
+ {145, SWT.SCROLL_LOCK},
+ {44, SWT.PRINT_SCREEN},
+ {6, SWT.HELP},
+ {19, SWT.PAUSE},
+ {3, SWT.BREAK},
+
+ /* Safari-specific */
+ {186, ';'},
+ {187, '='},
+ {189, '-'},
+ };
+
+public class EvaluateFunction extends BrowserFunction {
+ public EvaluateFunction (Browser browser, String name) {
+ super (browser, name, false);
+ }
+ public Object function (Object[] arguments) {
+ if (arguments[0] instanceof String) {
+ String string = (String)arguments[0];
+ if (string.startsWith (ERROR_ID)) {
+ String errorString = ExtractError (string);
+ if (errorString.length () > 0) {
+ evaluateResult = new SWTException (SWT.ERROR_FAILED_EVALUATE, errorString);
+ } else {
+ evaluateResult = new SWTException (SWT.ERROR_FAILED_EVALUATE);
+ }
+ return null;
+ }
+ }
+ evaluateResult = arguments[0];
+ return null;
+ }
+}
+
+public void addAuthenticationListener (AuthenticationListener listener) {
+ AuthenticationListener[] newAuthenticationListeners = new AuthenticationListener[authenticationListeners.length + 1];
+ System.arraycopy(authenticationListeners, 0, newAuthenticationListeners, 0, authenticationListeners.length);
+ authenticationListeners = newAuthenticationListeners;
+ authenticationListeners[authenticationListeners.length - 1] = listener;
+}
+
+public void addCloseWindowListener (CloseWindowListener listener) {
+ CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length + 1];
+ System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, closeWindowListeners.length);
+ closeWindowListeners = newCloseWindowListeners;
+ closeWindowListeners[closeWindowListeners.length - 1] = listener;
+}
+
+public void addLocationListener (LocationListener listener) {
+ LocationListener[] newLocationListeners = new LocationListener[locationListeners.length + 1];
+ System.arraycopy(locationListeners, 0, newLocationListeners, 0, locationListeners.length);
+ locationListeners = newLocationListeners;
+ locationListeners[locationListeners.length - 1] = listener;
+}
+
+public void addOpenWindowListener (OpenWindowListener listener) {
+ OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length + 1];
+ System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, openWindowListeners.length);
+ openWindowListeners = newOpenWindowListeners;
+ openWindowListeners[openWindowListeners.length - 1] = listener;
+}
+
+public void addProgressListener (ProgressListener listener) {
+ ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length + 1];
+ System.arraycopy(progressListeners, 0, newProgressListeners, 0, progressListeners.length);
+ progressListeners = newProgressListeners;
+ progressListeners[progressListeners.length - 1] = listener;
+}
+
+public void addStatusTextListener (StatusTextListener listener) {
+ StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length + 1];
+ System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, statusTextListeners.length);
+ statusTextListeners = newStatusTextListeners;
+ statusTextListeners[statusTextListeners.length - 1] = listener;
+}
+
+public void addTitleListener (TitleListener listener) {
+ TitleListener[] newTitleListeners = new TitleListener[titleListeners.length + 1];
+ System.arraycopy(titleListeners, 0, newTitleListeners, 0, titleListeners.length);
+ titleListeners = newTitleListeners;
+ titleListeners[titleListeners.length - 1] = listener;
+}
+
+public void addVisibilityWindowListener (VisibilityWindowListener listener) {
+ VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length + 1];
+ System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, visibilityWindowListeners.length);
+ visibilityWindowListeners = newVisibilityWindowListeners;
+ visibilityWindowListeners[visibilityWindowListeners.length - 1] = listener;
+}
+
+public abstract boolean back ();
+
+public static void clearSessions () {
+ if (NativeClearSessions != null) NativeClearSessions.run ();
+ if (MozillaClearSessions != null) MozillaClearSessions.run ();
+}
+
+public static String GetCookie (String name, String url) {
+ CookieName = name; CookieUrl = url;
+ if (NativeGetCookie != null) NativeGetCookie.run ();
+ if (MozillaGetCookie != null) MozillaGetCookie.run ();
+ String result = CookieValue;
+ CookieName = CookieValue = CookieUrl = null;
+ return result;
+}
+
+public static boolean SetCookie (String value, String url) {
+ CookieValue = value; CookieUrl = url;
+ CookieResult = false;
+ if (NativeSetCookie != null) NativeSetCookie.run ();
+ if (MozillaSetCookie != null) MozillaSetCookie.run ();
+ CookieValue = CookieUrl = null;
+ return CookieResult;
+}
+
+public abstract void create (Composite parent, int style);
+
+static String CreateErrorString (String error) {
+ return ERROR_ID + error;
+}
+
+static String ExtractError (String error) {
+ return error.substring (ERROR_ID.length ());
+}
+
+public void createFunction (BrowserFunction function) {
+ /*
+ * If an existing function with the same name is found then
+ * remove it so that it is not recreated on subsequent pages
+ * (the new function overwrites the old one).
+ */
+ Enumeration keys = functions.keys ();
+ while (keys.hasMoreElements ()) {
+ Object key = keys.nextElement ();
+ BrowserFunction current = (BrowserFunction)functions.get (key);
+ if (current.name.equals (function.name)) {
+ functions.remove (key);
+ break;
+ }
+ }
+
+ function.index = getNextFunctionIndex ();
+ registerFunction (function);
+
+ StringBuffer buffer = new StringBuffer ("window."); //$NON-NLS-1$
+ buffer.append (function.name);
+ buffer.append (" = function "); //$NON-NLS-1$
+ buffer.append (function.name);
+ buffer.append ("() {var result = window.external.callJava("); //$NON-NLS-1$
+ buffer.append (function.index);
+ buffer.append (",Array.prototype.slice.call(arguments)); if (typeof result == 'string' && result.indexOf('"); //$NON-NLS-1$
+ buffer.append (ERROR_ID);
+ buffer.append ("') == 0) {var error = new Error(result.substring("); //$NON-NLS-1$
+ buffer.append (ERROR_ID.length ());
+ buffer.append (")); throw error;} return result;};"); //$NON-NLS-1$
+ buffer.append ("for (var i = 0; i < frames.length; i++) {try { frames[i]."); //$NON-NLS-1$
+ buffer.append (function.name);
+ buffer.append (" = window."); //$NON-NLS-1$
+ buffer.append (function.name);
+ buffer.append (";} catch (e) {} };"); //$NON-NLS-1$
+ function.functionString = buffer.toString ();
+ execute (function.functionString);
+}
+
+void deregisterFunction (BrowserFunction function) {
+ functions.remove (new Integer (function.index));
+}
+
+public void destroyFunction (BrowserFunction function) {
+ String deleteString = getDeleteFunctionString (function.name);
+ StringBuffer buffer = new StringBuffer ("for (var i = 0; i < frames.length; i++) {try {frames[i].eval(\""); //$NON-NLS-1$
+ buffer.append (deleteString);
+ buffer.append ("\");} catch (e) {}}"); //$NON-NLS-1$
+ execute (buffer.toString ());
+ execute (deleteString);
+ deregisterFunction (function);
+}
+
+public abstract boolean execute (String script);
+
+public Object evaluate (String script) throws SWTException {
+ BrowserFunction function = new EvaluateFunction (browser, ""); // $NON-NLS-1$
+ int index = getNextFunctionIndex ();
+ function.index = index;
+ function.isEvaluate = true;
+ registerFunction (function);
+ String functionName = EXECUTE_ID + index;
+
+ StringBuffer buffer = new StringBuffer ("window."); // $NON-NLS-1$
+ buffer.append (functionName);
+ buffer.append (" = function "); // $NON-NLS-1$
+ buffer.append (functionName);
+ buffer.append ("() {\n"); // $NON-NLS-1$
+ buffer.append (script);
+ buffer.append ("\n};"); // $NON-NLS-1$
+ execute (buffer.toString ());
+
+ buffer = new StringBuffer ("if (window."); // $NON-NLS-1$
+ buffer.append (functionName);
+ buffer.append (" == undefined) {window.external.callJava("); // $NON-NLS-1$
+ buffer.append (index);
+ buffer.append (", ['"); // $NON-NLS-1$
+ buffer.append (ERROR_ID);
+ buffer.append ("']);} else {try {var result = "); // $NON-NLS-1$
+ buffer.append (functionName);
+ buffer.append ("(); window.external.callJava("); // $NON-NLS-1$
+ buffer.append (index);
+ buffer.append (", [result]);} catch (e) {window.external.callJava("); // $NON-NLS-1$
+ buffer.append (index);
+ buffer.append (", ['"); // $NON-NLS-1$
+ buffer.append (ERROR_ID);
+ buffer.append ("' + e.message]);}}"); // $NON-NLS-1$
+ execute (buffer.toString ());
+ execute (getDeleteFunctionString (functionName));
+ deregisterFunction (function);
+
+ Object result = evaluateResult;
+ evaluateResult = null;
+ if (result instanceof SWTException) throw (SWTException)result;
+ return result;
+}
+
+public abstract boolean forward ();
+
+public abstract String getBrowserType ();
+
+String getDeleteFunctionString (String functionName) {
+ return "delete window." + functionName; //$NON-NLS-1$
+}
+
+int getNextFunctionIndex () {
+ return nextFunctionIndex++;
+}
+
+public abstract String getText ();
+
+public abstract String getUrl ();
+
+public Object getWebBrowser () {
+ return null;
+}
+
+public abstract boolean isBackEnabled ();
+
+public boolean isFocusControl () {
+ return false;
+}
+
+public abstract boolean isForwardEnabled ();
+
+public abstract void refresh ();
+
+void registerFunction (BrowserFunction function) {
+ functions.put (new Integer (function.index), function);
+}
+
+public void removeAuthenticationListener (AuthenticationListener listener) {
+ if (authenticationListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < authenticationListeners.length; i++) {
+ if (listener == authenticationListeners[i]) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (authenticationListeners.length == 1) {
+ authenticationListeners = new AuthenticationListener[0];
+ return;
+ }
+ AuthenticationListener[] newAuthenticationListeners = new AuthenticationListener[authenticationListeners.length - 1];
+ System.arraycopy (authenticationListeners, 0, newAuthenticationListeners, 0, index);
+ System.arraycopy (authenticationListeners, index + 1, newAuthenticationListeners, index, authenticationListeners.length - index - 1);
+ authenticationListeners = newAuthenticationListeners;
+}
+
+public void removeCloseWindowListener (CloseWindowListener listener) {
+ if (closeWindowListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < closeWindowListeners.length; i++) {
+ if (listener == closeWindowListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (closeWindowListeners.length == 1) {
+ closeWindowListeners = new CloseWindowListener[0];
+ return;
+ }
+ CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length - 1];
+ System.arraycopy (closeWindowListeners, 0, newCloseWindowListeners, 0, index);
+ System.arraycopy (closeWindowListeners, index + 1, newCloseWindowListeners, index, closeWindowListeners.length - index - 1);
+ closeWindowListeners = newCloseWindowListeners;
+}
+
+public void removeLocationListener (LocationListener listener) {
+ if (locationListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < locationListeners.length; i++) {
+ if (listener == locationListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (locationListeners.length == 1) {
+ locationListeners = new LocationListener[0];
+ return;
+ }
+ LocationListener[] newLocationListeners = new LocationListener[locationListeners.length - 1];
+ System.arraycopy (locationListeners, 0, newLocationListeners, 0, index);
+ System.arraycopy (locationListeners, index + 1, newLocationListeners, index, locationListeners.length - index - 1);
+ locationListeners = newLocationListeners;
+}
+
+public void removeOpenWindowListener (OpenWindowListener listener) {
+ if (openWindowListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < openWindowListeners.length; i++) {
+ if (listener == openWindowListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (openWindowListeners.length == 1) {
+ openWindowListeners = new OpenWindowListener[0];
+ return;
+ }
+ OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length - 1];
+ System.arraycopy (openWindowListeners, 0, newOpenWindowListeners, 0, index);
+ System.arraycopy (openWindowListeners, index + 1, newOpenWindowListeners, index, openWindowListeners.length - index - 1);
+ openWindowListeners = newOpenWindowListeners;
+}
+
+public void removeProgressListener (ProgressListener listener) {
+ if (progressListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < progressListeners.length; i++) {
+ if (listener == progressListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (progressListeners.length == 1) {
+ progressListeners = new ProgressListener[0];
+ return;
+ }
+ ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length - 1];
+ System.arraycopy (progressListeners, 0, newProgressListeners, 0, index);
+ System.arraycopy (progressListeners, index + 1, newProgressListeners, index, progressListeners.length - index - 1);
+ progressListeners = newProgressListeners;
+}
+
+public void removeStatusTextListener (StatusTextListener listener) {
+ if (statusTextListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ if (listener == statusTextListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (statusTextListeners.length == 1) {
+ statusTextListeners = new StatusTextListener[0];
+ return;
+ }
+ StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length - 1];
+ System.arraycopy (statusTextListeners, 0, newStatusTextListeners, 0, index);
+ System.arraycopy (statusTextListeners, index + 1, newStatusTextListeners, index, statusTextListeners.length - index - 1);
+ statusTextListeners = newStatusTextListeners;
+}
+
+public void removeTitleListener (TitleListener listener) {
+ if (titleListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < titleListeners.length; i++) {
+ if (listener == titleListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (titleListeners.length == 1) {
+ titleListeners = new TitleListener[0];
+ return;
+ }
+ TitleListener[] newTitleListeners = new TitleListener[titleListeners.length - 1];
+ System.arraycopy (titleListeners, 0, newTitleListeners, 0, index);
+ System.arraycopy (titleListeners, index + 1, newTitleListeners, index, titleListeners.length - index - 1);
+ titleListeners = newTitleListeners;
+}
+
+public void removeVisibilityWindowListener (VisibilityWindowListener listener) {
+ if (visibilityWindowListeners.length == 0) return;
+ int index = -1;
+ for (int i = 0; i < visibilityWindowListeners.length; i++) {
+ if (listener == visibilityWindowListeners[i]){
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) return;
+ if (visibilityWindowListeners.length == 1) {
+ visibilityWindowListeners = new VisibilityWindowListener[0];
+ return;
+ }
+ VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length - 1];
+ System.arraycopy (visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, index);
+ System.arraycopy (visibilityWindowListeners, index + 1, newVisibilityWindowListeners, index, visibilityWindowListeners.length - index - 1);
+ visibilityWindowListeners = newVisibilityWindowListeners;
+}
+
+public void setBrowser (Browser browser) {
+ this.browser = browser;
+}
+
+public abstract boolean setText (String html);
+
+public abstract boolean setUrl (String url);
+
+public abstract void stop ();
+
+int translateKey (int key) {
+ for (int i = 0; i < KeyTable.length; i++) {
+ if (KeyTable[i][0] == key) return KeyTable[i][1];
+ }
+ return 0;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WindowEvent.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WindowEvent.java
new file mode 100644
index 0000000000..ae7551533a
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/WindowEvent.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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 org.eclipse.swt.widgets.*;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+
+/**
+ * A <code>WindowEvent</code> is sent by a {@link Browser} when
+ * a new window needs to be created or when an existing window needs to be
+ * closed. This notification occurs when a javascript command such as
+ * <code>window.open</code> or <code>window.close</code> gets executed by
+ * a <code>Browser</code>.
+ *
+ * <p>
+ * The following example shows how <code>WindowEvent</code>'s are typically
+ * handled.
+ *
+ * <code><pre>
+ * public static void main(String[] args) {
+ * Display display = new Display();
+ * Shell shell = new Shell(display);
+ * shell.setText("Main Window");
+ * shell.setLayout(new FillLayout());
+ * Browser browser = new Browser(shell, SWT.NONE);
+ * initialize(display, browser);
+ * shell.open();
+ * browser.setUrl("http://www.eclipse.org");
+ * while (!shell.isDisposed()) {
+ * if (!display.readAndDispatch())
+ * display.sleep();
+ * }
+ * display.dispose();
+ * }
+ *
+ * static void initialize(final Display display, Browser browser) {
+ * browser.addOpenWindowListener(new OpenWindowListener() {
+ * public void open(WindowEvent event) {
+ * // Certain platforms can provide a default full browser.
+ * // simply return in that case if the application prefers
+ * // the default full browser to the embedded one set below.
+ * if (!event.required) return;
+ *
+ * // Embed the new window
+ * Shell shell = new Shell(display);
+ * shell.setText("New Window");
+ * shell.setLayout(new FillLayout());
+ * Browser browser = new Browser(shell, SWT.NONE);
+ * initialize(display, browser);
+ * event.browser = browser;
+ * }
+ * });
+ * browser.addVisibilityWindowListener(new VisibilityWindowListener() {
+ * public void hide(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * shell.setVisible(false);
+ * }
+ * public void show(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * if (event.location != null) shell.setLocation(event.location);
+ * if (event.size != null) {
+ * Point size = event.size;
+ * shell.setSize(shell.computeSize(size.x, size.y));
+ * }
+ * if (event.addressBar || event.menuBar || event.statusBar || event.toolBar) {
+ * // Create widgets for the address bar, menu bar, status bar and/or tool bar
+ * // leave enough space in the Shell to accommodate a Browser of the size
+ * // given by event.size
+ * }
+ * shell.open();
+ * }
+ * });
+ * browser.addCloseWindowListener(new CloseWindowListener() {
+ * public void close(WindowEvent event) {
+ * Browser browser = (Browser)event.widget;
+ * Shell shell = browser.getShell();
+ * shell.close();
+ * }
+ * });
+ * }
+ * </pre></code>
+ *
+ * The following notifications are emitted when the user selects a hyperlink that targets a new window
+ * or as the result of a javascript that executes window.open.
+ *
+ * <p>Main Browser
+ * <ul>
+ * <li>User selects a link that opens in a new window or javascript requests a new window</li>
+ * <li>OpenWindowListener.open() notified</li>
+ * <ul>
+ * <li>Application creates a new Shell and a second Browser inside that Shell</li>
+ * <li>Application registers WindowListener's on that second Browser, such as VisibilityWindowListener</li>
+ * <li>Application returns the second Browser as the host for the new window content</li>
+ * </ul>
+ * </ul>
+ *
+ * <p>Second Browser
+ * <ul>
+ * <li>VisibilityWindowListener.show() notified</li>
+ * <ul>
+ * <li>Application sets navigation tool bar, status bar, menu bar and Shell size
+ * <li>Application makes the Shell hosting the second Browser visible
+ * <li>User now sees the new window
+ * </ul>
+ * </ul>
+ *
+ * @see CloseWindowListener
+ * @see OpenWindowListener
+ * @see VisibilityWindowListener
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public class WindowEvent extends TypedEvent {
+
+ /**
+ * Specifies whether the platform requires the user to provide a
+ * <code>Browser</code> to handle the new window.
+ *
+ * @since 3.1
+ */
+ public boolean required;
+
+
+ /**
+ * <code>Browser</code> provided by the application.
+ */
+ public Browser browser;
+
+ /**
+ * Requested location for the <code>Shell</code> hosting the <code>Browser</code>.
+ * It is <code>null</code> if no location has been requested.
+ */
+ public Point location;
+
+ /**
+ * Requested <code>Browser</code> size. The client area of the <code>Shell</code>
+ * hosting the <code>Browser</code> should be large enough to accommodate that size.
+ * It is <code>null</code> if no size has been requested.
+ */
+ public Point size;
+
+ /**
+ * Specifies whether the <code>Shell</code> hosting the <code>Browser</code> should
+ * display an address bar.
+ *
+ * @since 3.1
+ */
+ public boolean addressBar;
+
+ /**
+ * Specifies whether the <code>Shell</code> hosting the <code>Browser</code> should
+ * display a menu bar. Note that this is always <code>true</code> on OS X.
+ *
+ * @since 3.1
+ */
+ public boolean menuBar;
+
+ /**
+ * Specifies whether the <code>Shell</code> hosting the <code>Browser</code> should
+ * display a status bar.
+ *
+ * @since 3.1
+ */
+ public boolean statusBar;
+
+ /**
+ * Specifies whether the <code>Shell</code> hosting the <code>Browser</code> should
+ * display a tool bar.
+ *
+ * @since 3.1
+ */
+ public boolean toolBar;
+
+ static final long serialVersionUID = 3617851997387174969L;
+
+/**
+ * Constructs a new instance of this class.
+ *
+ * @param widget the widget that fired the event
+ *
+ * @since 3.5
+ */
+public WindowEvent(Widget widget) {
+ super(widget);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the event
+ */
+public String toString() {
+ String string = super.toString ();
+ return string.substring (0, string.length() - 1) // remove trailing '}'
+ + " required=" + required
+ + " browser=" + browser
+ + " location=" + location
+ + " size=" + size
+ + " addressBar=" + addressBar
+ + " menuBar=" + menuBar
+ + " statusBar=" + statusBar
+ + " toolBar=" + toolBar
+ + "}";
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/package.html b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/package.html
new file mode 100644
index 0000000000..f64b6c4847
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/common/org/eclipse/swt/browser/package.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="Author" content="IBM">
+ <title>Package-level Javadoc</title>
+</head>
+<body>
+SWT Browser widget.
+<h2>
+Package Specification</h2>
+This package provides the classes to implement the browser user interface
+metaphor.
+</body>
+</html>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/forms/org/eclipse/swt/browser/IE.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/forms/org/eclipse/swt/browser/IE.java
new file mode 100644
index 0000000000..4a52398af0
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/forms/org/eclipse/swt/browser/IE.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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 org.eclipse.swt.*;
+import org.eclipse.swt.internal.wpf.*;
+import org.eclipse.swt.widgets.*;
+
+class IE extends WebBrowser {
+
+ int webBrowser, host, jniRef;
+
+ boolean ignoreDispose;
+
+ static {
+ NativeClearSessions = new Runnable() {
+ public void run() {
+// OS.InternetSetOption (0, OS.INTERNET_OPTION_END_BROWSER_SESSION, 0, 0);
+ }
+ };
+ }
+
+public void create(Composite parent, int style) {
+ host = OS.gcnew_WindowsFormsHost();
+ if (host == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ webBrowser = OS.gcnew_WebBrowser();
+ if (webBrowser == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.WindowsFormsHost_Child(host, webBrowser);
+ jniRef = OS.NewGlobalRef(this);
+ if (jniRef == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.WebBrowser_ScriptErrorsSuppressed(webBrowser, true);
+ int handler = OS.gcnew_WebBrowserNavigatingEventHandler(jniRef, "HandleNavigating");
+ OS.WebBrowser_Navigating(webBrowser, handler);
+ OS.GCHandle_Free(handler);
+ handler = OS.gcnew_WebBrowserProgressChangedEventHandler(jniRef, "HandleProgressChanged");
+ OS.WebBrowser_ProgressChanged(webBrowser, handler);
+ OS.GCHandle_Free(handler);
+ handler = OS.gcnew_EventHandler(jniRef, "HandleStatusTextChanged");
+ OS.WebBrowser_StatusTextChanged(webBrowser, handler);
+ OS.GCHandle_Free(handler);
+ handler = OS.gcnew_EventHandler(jniRef, "HandleDocumentTitleChanged");
+ OS.WebBrowser_DocumentTitleChanged(webBrowser, handler);
+ OS.GCHandle_Free(handler);
+ handler = OS.gcnew_WebBrowserDocumentCompletedEventHandler(jniRef, "HandleDocumentCompleted");
+ OS.WebBrowser_DocumentCompleted(webBrowser, handler);
+ OS.GCHandle_Free(handler);
+
+ int parentHandle = browser.handle;
+ int children = OS.Panel_Children(parentHandle);
+ OS.UIElementCollection_Insert(children, 0, host);
+ OS.GCHandle_Free(children);
+ OS.FrameworkElement_Width(host, OS.FrameworkElement_Width(parentHandle));
+ OS.FrameworkElement_Height(host, OS.FrameworkElement_Height(parentHandle));
+
+ Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+ switch (event.type) {
+ case SWT.Dispose: {
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (event.type, event);
+ event.type = SWT.NONE;
+ OS.GCHandle_Free(host);
+ OS.GCHandle_Free(webBrowser);
+ OS.DeleteGlobalRef(jniRef);
+ host = webBrowser = jniRef = 0;
+ break;
+ }
+ case SWT.Resize: {
+ OS.FrameworkElement_Width(host, OS.FrameworkElement_Width(browser.handle));
+ OS.FrameworkElement_Height(host, OS.FrameworkElement_Height(browser.handle));
+ break;
+ }
+ }
+ }
+ };
+ browser.addListener(SWT.Resize, listener);
+ browser.addListener(SWT.Dispose, listener);
+}
+
+public boolean back() {
+ return OS.WebBrowser_GoBack(webBrowser);
+}
+
+public boolean execute(String script) {
+// int document = OS.WebBrowser_Document(frame);
+// int length = script.length ();
+// char [] buffer = new char [length + 1];
+// script.getChars (0, length, buffer, 0);
+// int str = OS.gcnew_String (buffer);
+// int result = OS.HtmlDocument_InvokeScript(document, str);
+// OS.GCHandle_Free(result);
+// OS.GCHandle_Free(str);
+// OS.GCHandle_Free(document);
+ return true;
+}
+
+public boolean forward() {
+ return OS.WebBrowser_GoForward(webBrowser);
+}
+
+public String getBrowserType () {
+ return "ie"; //$NON-NLS-1$
+}
+
+public String getText () {
+ // TODO
+ return ""; //$NON-NLS-1$
+}
+
+public String getUrl() {
+ int uri = OS.WebBrowser_Url(webBrowser);
+ String url = getUriString (uri);
+ if (uri != 0) OS.GCHandle_Free(uri);
+ return url;
+}
+
+String getUriString(int uri) {
+ if (uri == 0) return null;
+ int str = OS.Object_ToString(uri);
+ int charArray = OS.String_ToCharArray(str);
+ char[] chars = new char[OS.String_Length(str)];
+ OS.memcpy(chars, charArray, chars.length * 2);
+ OS.GCHandle_Free(charArray);
+ String url = new String(chars);
+ OS.GCHandle_Free(str);
+ return url;
+}
+
+void HandleDocumentCompleted(int sender, int e) {
+ if (webBrowser == 0) return;
+ int uri = OS.WebBrowserDocumentCompletedEventArgs_Url(e);
+ String url = getUriString (uri);
+ if (uri != 0) OS.GCHandle_Free(uri);
+ LocationEvent newEvent = new LocationEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.location = url;
+ newEvent.doit = true;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changing(newEvent);
+ }
+ if (browser.isDisposed()) return;
+ ProgressEvent progressEvent = new ProgressEvent(browser);
+ progressEvent.display = browser.getDisplay();
+ progressEvent.widget = browser;
+ for (int i = 0; i < progressListeners.length; i++) {
+ progressListeners[i].completed(progressEvent);
+ }
+}
+
+void HandleDocumentTitleChanged(int sender, int e) {
+ if (webBrowser == 0) return;
+ int str = OS.WebBrowser_DocumentTitle(webBrowser);
+ String title = "";
+ if (str != 0) {
+ int charArray = OS.String_ToCharArray(str);
+ char[] chars = new char[OS.String_Length(str)];
+ OS.memcpy(chars, charArray, chars.length * 2);
+ OS.GCHandle_Free(charArray);
+ OS.GCHandle_Free(str);
+ title = new String(chars);
+ }
+ TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.title = title;
+ for (int i = 0; i < titleListeners.length; i++) {
+ titleListeners[i].changed(newEvent);
+ }
+}
+
+void HandleNavigating(int sender, int e) {
+ if (webBrowser == 0) return;
+ int uri = OS.WebBrowserNavigatingEventArgs_Url(e);
+ String url = getUriString (uri);
+ if (uri != 0) OS.GCHandle_Free(uri);
+ LocationEvent newEvent = new LocationEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.location = url;
+ newEvent.doit = true;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changing(newEvent);
+ }
+}
+
+void HandleProgressChanged(int sender, int e) {
+ if (webBrowser == 0) return;
+ long nProgress = OS.WebBrowserProgressChangedEventArgs_CurrentProgress(e);
+ long nProgressMax = OS.WebBrowserProgressChangedEventArgs_MaximumProgress(e);
+ if (nProgress != -1) {
+ ProgressEvent newEvent = new ProgressEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.current = (int)nProgress;
+ newEvent.total = (int)nProgressMax;
+ for (int i = 0; i < progressListeners.length; i++) {
+ progressListeners[i].changed(newEvent);
+ }
+ }
+}
+
+void HandleStatusTextChanged(int sender, int e) {
+ if (webBrowser == 0) return;
+ int str = OS.WebBrowser_StatusText(webBrowser);
+ String text = "";
+ if (str != 0) {
+ int charArray = OS.String_ToCharArray(str);
+ char[] chars = new char[OS.String_Length(str)];
+ OS.memcpy(chars, charArray, chars.length * 2);
+ OS.GCHandle_Free(charArray);
+ OS.GCHandle_Free(str);
+ text = new String(chars);
+ }
+ StatusTextEvent newEvent = new StatusTextEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.text = text;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(newEvent);
+ }
+}
+
+public boolean isBackEnabled() {
+ return OS.WebBrowser_CanGoBack(webBrowser);
+}
+
+public boolean isForwardEnabled() {
+ return OS.WebBrowser_CanGoForward(webBrowser);
+}
+
+public void refresh() {
+ OS.WebBrowser_Refresh(webBrowser);
+}
+
+public boolean setText(String html) {
+ int state = OS.WebBrowser_ReadyState(webBrowser);
+ if (!(state == OS.WebBrowserReadyState_Uninitialized || state == OS.WebBrowserReadyState_Complete)) {
+ OS.WebBrowser_Stop(webBrowser);
+ }
+ int length = html.length ();
+ char [] buffer = new char [length + 1];
+ html.getChars (0, length, buffer, 0);
+ int str = OS.gcnew_String (buffer);
+ if (str == 0) SWT.error (SWT.ERROR_NO_HANDLES);
+ OS.WebBrowser_DocumentText(webBrowser, str);
+ OS.GCHandle_Free(str);
+ return true;
+}
+
+public boolean setUrl(String url) {
+ int state = OS.WebBrowser_ReadyState(webBrowser);
+ if (!(state == OS.WebBrowserReadyState_Uninitialized || state == OS.WebBrowserReadyState_Complete)) {
+ OS.WebBrowser_Stop(webBrowser);
+ }
+ int length = url.length ();
+ char [] buffer = new char [length + 1];
+ url.getChars (0, length, buffer, 0);
+ int str = OS.gcnew_String (buffer);
+ OS.WebBrowser_Navigate(webBrowser, str);
+ OS.GCHandle_Free(str);
+ return true;
+}
+
+public void stop() {
+ OS.WebBrowser_Stop(webBrowser);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/photon/org/eclipse/swt/browser/Voyager.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/photon/org/eclipse/swt/browser/Voyager.java
new file mode 100755
index 0000000000..075ac65fe5
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/photon/org/eclipse/swt/browser/Voyager.java
@@ -0,0 +1,469 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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:
+ * Chris McKillop (QNX Software Systems) - initial implementation
+ *******************************************************************************/
+package org.eclipse.swt.browser;
+
+import java.io.File;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.photon.*;
+import org.eclipse.swt.widgets.*;
+
+class Voyager extends WebBrowser {
+ int webHandle;
+ String url = ""; //$NON-NLS-1$
+ String text = ""; //$NON-NLS-1$
+ int textOffset;
+ int currentProgress;
+ int totalProgress = 25;
+ /* browser to redirect content to */
+ Browser redirectBrowser;
+ static int instanceCount = 0;
+
+ /* Package Name */
+ static Callback callback;
+
+public void create(Composite parent, int style) {
+ /* use Photon's built-in anchoring for resizing */
+ int[] args = {
+ OS.Pt_ARG_ANCHOR_FLAGS,
+ OS.Pt_TOP_ANCHORED_TOP | OS.Pt_BOTTOM_ANCHORED_BOTTOM | OS.Pt_LEFT_ANCHORED_LEFT | OS.Pt_RIGHT_ANCHORED_RIGHT,
+ OS.Pt_TOP_ANCHORED_TOP | OS.Pt_BOTTOM_ANCHORED_BOTTOM | OS.Pt_LEFT_ANCHORED_LEFT | OS.Pt_RIGHT_ANCHORED_RIGHT,
+ OS.Pt_ARG_FILL_COLOR,
+ 0xFFFFFF,
+ 0 };
+ webHandle = OS.PtCreateWidget(OS.PtWebClient(), browser.handle, args.length / 3, args);
+ if (webHandle == 0) {
+ browser.dispose();
+ SWT.error (SWT.ERROR_NO_HANDLES);
+ }
+
+ /* configure the widget with a specific server */
+ File netfront = new File("/usr/photon/bin/netfront"); //$NON-NLS-1$
+ String name, server;
+ if (netfront.exists() || (OS.QNX_MAJOR >= 6 && OS.QNX_MINOR >= 3 && OS.QNX_MICRO >= 0)) {
+ name = "NetfrontServer"; //$NON-NLS-1$
+ server = "netfront"; //$NON-NLS-1$
+ } else {
+ name = "VoyagerServer-2"; //$NON-NLS-1$
+ server = "vserver"; //$NON-NLS-1$
+ }
+ /* set client name */
+ byte[] nameBuffer = Converter.wcsToMbcs(null, name, true);
+ int namePtr = OS.malloc(nameBuffer.length);
+ OS.memmove(namePtr, nameBuffer, nameBuffer.length);
+ OS.PtSetResource(webHandle, OS.Pt_ARG_CLIENT_NAME, namePtr, 0);
+ OS.free(namePtr);
+
+ /**
+ * Feature in Photon PtWebClient. If you give a server name
+ * when the widget is created it will attempt to start a new server
+ * rather then attaching a new window context to the existing server.
+ * If you don't connect to the existing one then javascript window
+ * creation will fail.
+ */
+ if (instanceCount == 0) {
+ /* select server */
+ byte[] serverBuffer = Converter.wcsToMbcs(null, server, true);
+ int serverPtr = OS.malloc(serverBuffer.length);
+ OS.memmove(serverPtr, serverBuffer, serverBuffer.length);
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_SERVER, serverPtr, 0);
+ OS.free(serverPtr);
+ }
+ instanceCount++;
+
+ if (callback == null) callback = new Callback(this.getClass(), "webProc", 3, false); //$NON-NLS-1$
+ int webProc = callback.getAddress();
+ if (webProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_CLOSE_WINDOW, webProc, OS.Pt_CB_WEB_CLOSE_WINDOW);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_COMPLETE, webProc, OS.Pt_CB_WEB_COMPLETE);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_DATA_REQ, webProc, OS.Pt_CB_WEB_DATA_REQ);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_METADATA, webProc, OS.Pt_CB_WEB_METADATA);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_NEW_WINDOW, webProc, OS.Pt_CB_WEB_NEW_WINDOW);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_START, webProc, OS.Pt_CB_WEB_START);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_STATUS, webProc, OS.Pt_CB_WEB_STATUS);
+ OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_URL, webProc, OS.Pt_CB_WEB_URL);
+ Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+ switch (event.type) {
+ case SWT.Dispose: onDispose(); break;
+ case SWT.FocusIn: onFocusGained(event); break;
+ }
+ }
+ };
+ int[] folderEvents = new int[]{
+ SWT.Dispose,
+ SWT.FocusIn,
+ };
+ for (int i = 0; i < folderEvents.length; i++) {
+ browser.addListener(folderEvents[i], listener);
+ }
+ OS.PtRealizeWidget(webHandle);
+}
+
+static int webProc(int handle, int data, int info) {
+ Display display = Display.getCurrent();
+ int parent = OS.PtWidgetParent (handle);
+ Widget widget = display.findWidget(parent);
+ if (widget != null && widget instanceof Browser) {
+ Browser browser = (Browser)widget;
+ return ((Voyager)browser.webBrowser).webProc(data, info);
+ }
+ return OS.Pt_CONTINUE;
+}
+
+public boolean back() {
+ int ptr = OS.malloc(4);
+ int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
+ OS.PtGetResources(webHandle, args.length / 3, args);
+ int[] result = new int[1];
+ OS.memmove(result, ptr, 4);
+ OS.memmove(result, result[0], 4);
+ OS.free(ptr);
+ if ((result[0] & (1 << OS.Pt_WEB_DIRECTION_BACK)) == 0) return false;
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_NAVIGATE_PAGE, OS.Pt_WEB_DIRECTION_BACK, 0);
+ return true;
+}
+
+int webProc(int data, int info) {
+ switch (data) {
+ case OS.Pt_CB_WEB_CLOSE_WINDOW: return Pt_CB_WEB_CLOSE_WINDOW(info);
+ case OS.Pt_CB_WEB_COMPLETE: return Pt_CB_WEB_COMPLETE(info);
+ case OS.Pt_CB_WEB_DATA_REQ: return Pt_CB_WEB_DATA_REQ(info);
+ case OS.Pt_CB_WEB_METADATA: return Pt_CB_WEB_METADATA(info);
+ case OS.Pt_CB_WEB_NEW_WINDOW: return Pt_CB_WEB_NEW_WINDOW(info);
+ case OS.Pt_CB_WEB_START: return Pt_CB_WEB_START(info);
+ case OS.Pt_CB_WEB_STATUS: return Pt_CB_WEB_STATUS(info);
+ case OS.Pt_CB_WEB_URL: return Pt_CB_WEB_URL(info);
+ }
+ return OS.Pt_CONTINUE;
+}
+
+public boolean execute(String script) {
+ return false;
+}
+
+public boolean forward() {
+ int ptr = OS.malloc(4);
+ int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
+ OS.PtGetResources(webHandle, args.length / 3, args);
+ int[] result = new int[1];
+ OS.memmove(result, ptr, 4);
+ OS.memmove(result, result[0], 4);
+ OS.free(ptr);
+ if ((result[0] & (1 << OS.Pt_WEB_DIRECTION_FWD)) == 0) return false;
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_NAVIGATE_PAGE, OS.Pt_WEB_DIRECTION_FWD, 0);
+ return true;
+}
+
+public String getBrowserType () {
+ return "voyager"; //$NON-NLS-1$
+}
+
+public String getText () {
+ // TODO
+ return ""; //$NON-NLS-1$
+}
+
+public String getUrl() {
+ return url;
+}
+
+public boolean isBackEnabled() {
+ int ptr = OS.malloc(4);
+ int[] args = new int[] {OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
+ OS.PtGetResources(webHandle, args.length / 3, args);
+ int[] result = new int[1];
+ OS.memmove(result, ptr, 4);
+ OS.memmove(result, result[0], 4);
+ OS.free(ptr);
+ return (result[0] & (1 << OS.Pt_WEB_DIRECTION_BACK)) != 0;
+}
+
+public boolean isForwardEnabled() {
+ int ptr = OS.malloc(4);
+ int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
+ OS.PtGetResources(webHandle, args.length / 3, args);
+ int[] result = new int[1];
+ OS.memmove(result, ptr, 4);
+ OS.memmove(result, result[0], 4);
+ OS.free(ptr);
+ return (result[0] & (1 << OS.Pt_WEB_DIRECTION_FWD)) != 0;
+}
+
+void onDispose() {
+ OS.PtDestroyWidget(webHandle);
+ webHandle = 0;
+ instanceCount--;
+}
+
+void onFocusGained(Event e) {
+ OS.PtContainerGiveFocus(webHandle, null);
+}
+
+int Pt_CB_WEB_CLOSE_WINDOW(int info) {
+ WindowEvent event = new WindowEvent(browser);
+ event.display = browser.getDisplay();
+ event.widget = browser;
+ for(int i = 0; i < closeWindowListeners.length; i++ )
+ closeWindowListeners[i].close(event);
+ browser.dispose();
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_COMPLETE(int info) {
+ Display display = browser.getDisplay();
+ LocationEvent event = new LocationEvent(browser);
+ event.display = display;
+ event.widget = browser;
+ event.location = url;
+ event.top = true;
+ for (int i = 0; i < locationListeners.length; i++)
+ locationListeners[i].changed(event);
+ ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = display;
+ progress.widget = browser;
+ progress.current = totalProgress;
+ progress.total = totalProgress;
+ for (int i = 0; i < progressListeners.length; i++)
+ progressListeners[i].completed(progress);
+ StatusTextEvent statusevent = new StatusTextEvent(browser);
+ statusevent.display = display;
+ statusevent.widget = browser;
+ statusevent.text = ""; //$NON-NLS-1$
+ for (int i = 0; i < statusTextListeners.length; i++)
+ statusTextListeners[i].changed(statusevent);
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_DATA_REQ(int info) {
+ PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
+ OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
+ PtWebDataReqCallback_t dataReq = new PtWebDataReqCallback_t();
+ OS.memmove(dataReq, cbinfo_t.cbdata, PtWebDataReqCallback_t.sizeof);
+ PtWebClient2Data_t clientData = new PtWebClient2Data_t();
+ clientData.type = dataReq.type;
+ clientData.data = 0;
+ String data = null;
+ switch (clientData.type) {
+ case OS.Pt_WEB_DATA_HEADER:
+ StringBuffer sb = new StringBuffer("Content-Type: text/html\n"); //$NON-NLS-1$
+ sb.append("Content-Length: "); //$NON-NLS-1$
+ sb.append(text.length());
+ sb.append("\n"); //$NON-NLS-1$
+ data = sb.toString();
+ break;
+ case OS.Pt_WEB_DATA_BODY:
+ /*
+ * Feature on Photon. The PtSetResource() call for PtWebClient data imposes
+ * a limit on the size of the text buffer being passed. The workaround is
+ * to break the text into 1KB chunks.
+ */
+ if (text.length() - textOffset > 1024) {
+ data = text.substring(textOffset, textOffset + 1024);
+ textOffset += 1024;
+ } else {
+ data = text.substring(textOffset);
+ }
+ break;
+ case OS.Pt_WEB_DATA_CLOSE:
+ text = ""; //$NON-NLS-1$
+ break;
+ }
+ if (data != null) {
+ byte[] buffer = Converter.wcsToMbcs(null, data, true);
+ clientData.data = OS.malloc(buffer.length);
+ OS.memmove(clientData.data, buffer, buffer.length);
+ clientData.length = buffer.length - 1;
+ }
+ dataReq.url = clientData.url;
+ int ptr = OS.malloc(PtWebClient2Data_t.sizeof);
+ OS.memmove(ptr, clientData, PtWebClient2Data_t.sizeof);
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_DATA, clientData.data, ptr);
+ OS.free(ptr);
+ if (clientData.data != 0) OS.free(clientData.data);
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_METADATA(int info) {
+ PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
+ OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
+ final PtWebMetaDataCallback_t webmeta_t = new PtWebMetaDataCallback_t();
+ OS.memmove(webmeta_t, cbinfo_t.cbdata, PtWebMetaDataCallback_t.sizeof);
+ String name = new String(webmeta_t.name, 0, OS.strlen(cbinfo_t.cbdata));
+ if (name.equals("title")) { //$NON-NLS-1$
+ String title = new String(webmeta_t.value, 0, OS.strlen(cbinfo_t.cbdata + webmeta_t.name.length));
+ TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.title = title;
+ /*
+ * Feature on Photon. The Voyager Browser updates the title section
+ * in the window decoration even if the title refers to an inner frame.
+ * Browsers on other platforms only update the title that refers to
+ * the top frame. As a result, the title event on Photon is sent for
+ * both top and inner frames.
+ */
+ for (int i = 0; i < titleListeners.length; i++)
+ titleListeners[i].changed(newEvent);
+ }
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_NEW_WINDOW(int info) {
+ PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
+ OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
+ final PtWebWindowCallback_t webwin_t = new PtWebWindowCallback_t();
+ OS.memmove(webwin_t,cbinfo_t.cbdata,PtWebWindowCallback_t.sizeof);
+ /*
+ * Feature on Photon. The server will use the first PtWebClient
+ * widget created from within the CB_WEB_NEW_WINDOW callback to
+ * host the new window. The workaround is to create a temporary
+ * PtWebClient widget everytime the notification is received.
+ * When its location is known, the Browser provided by the
+ * application is then redirected.
+ */
+ final Browser hidden = new Browser(browser.getParent(), SWT.NONE);
+ hidden.addLocationListener(new LocationListener() {
+ public void changed(org.eclipse.swt.browser.LocationEvent event) {
+ /*
+ * Bug on Voyager. The first PtWebClient widget created
+ * from within the CB_WEB_NEW_WINDOW callback is the one
+ * hosting the new window. For some reason, this PtWebClient
+ * widget may or may not receive a Pt_CB_WEB_URL
+ * notification. It receives a Pt_CB_WEB_COMPLETE in all cases.
+ * The workaround is to reload the content when this occurs.
+ * This request causes the Pt_CB_WEB_URL to be correctly sent,
+ * providing the information required to redirect the browser
+ * provided by the application.
+ */
+ if (event.location.length() == 0) {
+ hidden.refresh();
+ return;
+ }
+ hidden.dispose();
+ }
+ public void changing(final org.eclipse.swt.browser.LocationEvent event) {
+ Browser redirect = ((Voyager)hidden.webBrowser).redirectBrowser;
+ /* Forward the link to the Browser actually provided by the user */
+ if (redirect != null && !redirect.isDisposed()) {
+ WindowEvent newEvent = new WindowEvent(redirect);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = redirect;
+ newEvent.location = null;
+ /* Photon sets the size to 0,0 when it isn't specified. */
+ newEvent.size = webwin_t.size_w == 0 && webwin_t.size_h == 0 ? null : new Point(webwin_t.size_w, webwin_t.size_h);
+ for (int i = 0; i < redirect.webBrowser.visibilityWindowListeners.length; i++)
+ redirect.webBrowser.visibilityWindowListeners[i].show(newEvent);
+ redirect.setUrl(event.location);
+ }
+ }
+ });
+ WindowEvent event = new WindowEvent(browser);
+ event.display = browser.getDisplay();
+ event.widget = browser;
+ event.required = true;
+ for (int i = 0; i < openWindowListeners.length; i++)
+ openWindowListeners[i].open(event);
+ if (event.browser != null && !event.browser.isDisposed()) ((Voyager)hidden.webBrowser).redirectBrowser = event.browser;
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_START(int info) {
+ currentProgress = 1;
+ ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = browser.getDisplay();
+ progress.widget = browser;
+ progress.current = currentProgress;
+ progress.total = totalProgress;
+ for (int i = 0; i < progressListeners.length; i++)
+ progressListeners[i].changed(progress);
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_STATUS(int info) {
+ PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
+ PtWebStatusCallback_t webstatus = new PtWebStatusCallback_t();
+ OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
+ OS.memmove(webstatus, cbinfo_t.cbdata, PtWebStatusCallback_t.sizeof);
+ switch (webstatus.type) {
+ case OS.Pt_WEB_STATUS_MOUSE :
+ case OS.Pt_WEB_STATUS_PROGRESS :
+ StatusTextEvent statusevent = new StatusTextEvent(browser);
+ statusevent.display = browser.getDisplay();
+ statusevent.widget = browser;
+ statusevent.text = new String(webstatus.desc, 0, OS.strlen(cbinfo_t.cbdata));
+ for (int i = 0; i < statusTextListeners.length; i++)
+ statusTextListeners[i].changed(statusevent);
+ if (webstatus.type == OS.Pt_WEB_STATUS_PROGRESS) {
+ currentProgress++;
+ if (currentProgress >= totalProgress) currentProgress = 1;
+ ProgressEvent progress = new ProgressEvent(browser);
+ progress.display = browser.getDisplay();
+ progress.widget = browser;
+ progress.current = currentProgress;
+ progress.total = totalProgress;
+ for (int i = 0; i < progressListeners.length; i++)
+ progressListeners[i].changed(progress);
+ }
+ break;
+ }
+ return OS.Pt_CONTINUE;
+}
+
+int Pt_CB_WEB_URL(int info) {
+ PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
+ OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
+ byte[] buffer = new byte[OS.strlen(cbinfo_t.cbdata) + 1];
+ OS.memmove(buffer, cbinfo_t.cbdata, buffer.length);
+ url = new String(Converter.mbcsToWcs(null, buffer));
+ LocationEvent event = new LocationEvent(browser);
+ event.display = browser.getDisplay();
+ event.widget = browser;
+ event.location = url;
+ event.doit = true;
+ for (int i = 0; i < locationListeners.length; i++)
+ locationListeners[i].changing(event);
+ /* Widget could have been disposed */
+ if (browser.isDisposed()) return OS.Pt_CONTINUE;
+ if (!event.doit) stop();
+ return OS.Pt_CONTINUE;
+}
+
+public void refresh() {
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_RELOAD, 1, 0);
+}
+
+public boolean setText(String html) {
+ text = html;
+ textOffset = 0;
+ byte[] buffer = Converter.wcsToMbcs(null, "client:", true); //$NON-NLS-1$
+ int ptr = OS.malloc(buffer.length);
+ OS.memmove(ptr, buffer, buffer.length);
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_GET_URL, ptr, OS.Pt_WEB_ACTION_DISPLAY);
+ OS.free(ptr);
+ return true;
+}
+
+public boolean setUrl(String url) {
+ byte[] buffer = Converter.wcsToMbcs(null, url, true);
+ int ptr = OS.malloc(buffer.length);
+ OS.memmove(ptr, buffer, buffer.length);
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_GET_URL, ptr, OS.Pt_WEB_ACTION_DISPLAY);
+ OS.free(ptr);
+ return true;
+}
+
+public void stop() {
+ OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_STOP, 1, 0);
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/IE.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/IE.java
new file mode 100644
index 0000000000..7e8d713e4b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/IE.java
@@ -0,0 +1,1440 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2009 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.*;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.ole.win32.*;
+import org.eclipse.swt.widgets.*;
+
+class IE extends WebBrowser {
+
+ OleFrame frame;
+ OleControlSite site;
+ OleAutomation auto;
+ OleListener domListener;
+ OleAutomation[] documents = new OleAutomation[0];
+
+ boolean back, forward, navigate, delaySetText, ignoreDispose;
+ Point location;
+ Point size;
+ boolean addressBar = true, menuBar = true, statusBar = true, toolBar = true;
+ int /*long*/ globalDispatch;
+ String html, lastNavigateURL;
+ int style, lastKeyCode, lastCharCode;
+ int lastMouseMoveX, lastMouseMoveY;
+
+ static boolean IsIE7;
+ static String ProgId = "Shell.Explorer"; //$NON-NLS-1$
+
+ static final int BeforeNavigate2 = 0xfa;
+ static final int CommandStateChange = 0x69;
+ static final int DocumentComplete = 0x103;
+ static final int NavigateComplete2 = 0xfc;
+ static final int NewWindow2 = 0xfb;
+ static final int OnMenuBar = 0x100;
+ static final int OnStatusBar = 0x101;
+ static final int OnToolBar = 0xff;
+ static final int OnVisible = 0xfe;
+ static final int ProgressChange = 0x6c;
+ static final int RegisterAsBrowser = 0x228;
+ static final int StatusTextChange = 0x66;
+ static final int TitleChange = 0x71;
+ static final int WindowClosing = 0x107;
+ static final int WindowSetHeight = 0x10b;
+ static final int WindowSetLeft = 0x108;
+ static final int WindowSetResizable = 0x106;
+ static final int WindowSetTop = 0x109;
+ static final int WindowSetWidth = 0x10a;
+
+ static final short CSC_NAVIGATEFORWARD = 1;
+ static final short CSC_NAVIGATEBACK = 2;
+ static final int INET_E_DEFAULT_ACTION = 0x800C0011;
+ static final int READYSTATE_COMPLETE = 4;
+ static final int URLPOLICY_ALLOW = 0x00;
+ static final int URLPOLICY_DISALLOW = 0x03;
+ static final int URLPOLICY_JAVA_PROHIBIT = 0x0;
+ static final int URLPOLICY_JAVA_LOW = 0x00030000;
+ static final int URLZONE_LOCAL_MACHINE = 0;
+ static final int URLZONE_INTRANET = 1;
+ static final int URLACTION_ACTIVEX_MIN = 0x00001200;
+ static final int URLACTION_ACTIVEX_MAX = 0x000013ff;
+ static final int URLACTION_ACTIVEX_RUN = 0x00001200;
+ static final int URLACTION_JAVA_MIN = 0x00001C00;
+ static final int URLACTION_JAVA_MAX = 0x00001Cff;
+ static final int URLACTION_SCRIPT_RUN = 0x00001400;
+
+ static final int DISPID_AMBIENT_DLCONTROL = -5512;
+ static final int DLCTL_DLIMAGES = 0x00000010;
+ static final int DLCTL_VIDEOS = 0x00000020;
+ static final int DLCTL_BGSOUNDS = 0x00000040;
+ static final int DLCTL_NO_SCRIPTS = 0x00000080;
+ static final int DLCTL_NO_JAVA = 0x00000100;
+ static final int DLCTL_NO_RUNACTIVEXCTLS = 0x00000200;
+ static final int DLCTL_NO_DLACTIVEXCTLS = 0x00000400;
+ static final int DLCTL_DOWNLOADONLY = 0x00000800;
+ static final int DLCTL_NO_FRAMEDOWNLOAD = 0x00001000;
+ static final int DLCTL_RESYNCHRONIZE = 0x00002000;
+ static final int DLCTL_PRAGMA_NO_CACHE = 0x00004000;
+ static final int DLCTL_FORCEOFFLINE = 0x10000000;
+ static final int DLCTL_NO_CLIENTPULL = 0x20000000;
+ static final int DLCTL_SILENT = 0x40000000;
+ static final int DOCHOSTUIFLAG_THEME = 0x00040000;
+ static final int DOCHOSTUIFLAG_NO3DBORDER = 0x0000004;
+ static final int DOCHOSTUIFLAG_NO3DOUTERBORDER = 0x00200000;
+
+ static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
+ static final String CLSID_SHELLEXPLORER1 = "{EAB22AC3-30C1-11CF-A7EB-0000C05BAE0B}"; //$NON-NLS-1$
+ static final String EVENT_DOUBLECLICK = "dblclick"; //$NON-NLS-1$
+ static final String EVENT_DRAGEND = "dragend"; //$NON-NLS-1$
+ static final String EVENT_DRAGSTART = "dragstart"; //$NON-NLS-1$
+ static final String EVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
+ static final String EVENT_KEYPRESS = "keypress"; //$NON-NLS-1$
+ static final String EVENT_KEYUP = "keyup"; //$NON-NLS-1$
+ static final String EVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
+ static final String EVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+ static final String EVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
+ static final String EVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
+ static final String EVENT_MOUSEOUT = "mouseout"; //$NON-NLS-1$
+ static final String EVENT_MOUSEOVER = "mouseover"; //$NON-NLS-1$
+ static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
+ static final String PROPERTY_ALTKEY = "altKey"; //$NON-NLS-1$
+ static final String PROPERTY_BUTTON = "button"; //$NON-NLS-1$
+ static final String PROPERTY_CLIENTX = "clientX"; //$NON-NLS-1$
+ static final String PROPERTY_CLIENTY = "clientY"; //$NON-NLS-1$
+ static final String PROPERTY_CTRLKEY = "ctrlKey"; //$NON-NLS-1$
+ static final String PROPERTY_FROMELEMENT = "fromElement"; //$NON-NLS-1$
+ static final String PROPERTY_KEYCODE = "keyCode"; //$NON-NLS-1$
+ static final String PROPERTY_REPEAT = "repeat"; //$NON-NLS-1$
+ static final String PROPERTY_RETURNVALUE = "returnValue"; //$NON-NLS-1$
+ static final String PROPERTY_SHIFTKEY = "shiftKey"; //$NON-NLS-1$
+ static final String PROPERTY_TOELEMENT = "toElement"; //$NON-NLS-1$
+ static final String PROPERTY_TYPE = "type"; //$NON-NLS-1$
+ static final String PROPERTY_WHEELDELTA = "wheelDelta"; //$NON-NLS-1$
+
+ static {
+ NativeClearSessions = new Runnable() {
+ public void run() {
+ if (OS.IsPPC) return;
+ OS.InternetSetOption (0, OS.INTERNET_OPTION_END_BROWSER_SESSION, 0, 0);
+ }
+ };
+
+ NativeGetCookie = new Runnable () {
+ public void run () {
+ if (OS.IsPPC) return;
+ TCHAR url = new TCHAR (0, CookieUrl, true);
+ TCHAR cookieData = new TCHAR (0, 8192);
+ int[] size = new int[] {cookieData.length ()};
+ if (!OS.InternetGetCookie (url, null, cookieData, size)) {
+ /* original cookieData size was not large enough */
+ size[0] /= TCHAR.sizeof;
+ cookieData = new TCHAR (0, size[0]);
+ if (!OS.InternetGetCookie (url, null, cookieData, size)) return;
+ }
+ String allCookies = cookieData.toString (0, size[0]);
+ StringTokenizer tokenizer = new StringTokenizer (allCookies, ";"); //$NON-NLS-1$
+ while (tokenizer.hasMoreTokens ()) {
+ String cookie = tokenizer.nextToken ();
+ int index = cookie.indexOf ('=');
+ if (index != -1) {
+ String name = cookie.substring (0, index).trim ();
+ if (name.equals (CookieName)) {
+ CookieValue = cookie.substring (index + 1).trim ();
+ return;
+ }
+ }
+ }
+ }
+ };
+
+ NativeSetCookie = new Runnable () {
+ public void run () {
+ if (OS.IsPPC) return;
+ TCHAR url = new TCHAR (0, CookieUrl, true);
+ TCHAR value = new TCHAR (0, CookieValue, true);
+ CookieResult = OS.InternetSetCookie (url, null, value);
+ }
+ };
+
+ /*
+ * Registry entry HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Version indicates
+ * which version of IE is installed. Check this value in order to determine version-specific
+ * features that can be enabled.
+ */
+ TCHAR key = new TCHAR (0, "Software\\Microsoft\\Internet Explorer", true); //$NON-NLS-1$
+ int /*long*/ [] phkResult = new int /*long*/ [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_LOCAL_MACHINE, key, 0, OS.KEY_READ, phkResult) == 0) {
+ int [] lpcbData = new int [1];
+ TCHAR buffer = new TCHAR (0, "Version", true); //$NON-NLS-1$
+ int result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, (TCHAR) null, lpcbData);
+ if (result == 0) {
+ TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
+ result = OS.RegQueryValueEx (phkResult [0], buffer, 0, null, lpData, lpcbData);
+ if (result == 0) {
+ String versionString = lpData.toString (0, lpData.strlen ());
+ int index = versionString.indexOf ("."); //$NON-NLS-1$
+ if (index != -1) {
+ String majorString = versionString.substring (0, index);
+ int major = 0;
+ try {
+ major = Integer.valueOf (majorString).intValue ();
+ } catch (NumberFormatException e) {
+ /* just continue, version-specific features will not be enabled */
+ }
+ IsIE7 = major >= 7;
+ }
+ }
+ }
+ OS.RegCloseKey (phkResult [0]);
+ }
+
+ /*
+ * Registry entry HKEY_CLASSES_ROOT\Shell.Explorer\CLSID indicates which version of
+ * Shell.Explorer to use by default. We usually want to use this value because it
+ * typically points at the newest one that is available. However it is possible for
+ * this registry entry to be changed by another application to point at some other
+ * Shell.Explorer version.
+ *
+ * The Browser depends on the Shell.Explorer version being at least Shell.Explorer.2.
+ * If it is detected in the registry to be Shell.Explorer.1 then change the progId that
+ * will be embedded to explicitly specify Shell.Explorer.2.
+ */
+ key = new TCHAR (0, "Shell.Explorer\\CLSID", true); //$NON-NLS-1$
+ phkResult = new int /*long*/ [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult) == 0) {
+ int [] lpcbData = new int [1];
+ int result = OS.RegQueryValueEx (phkResult [0], null, 0, null, (TCHAR) null, lpcbData);
+ if (result == 0) {
+ TCHAR lpData = new TCHAR (0, lpcbData [0] / TCHAR.sizeof);
+ result = OS.RegQueryValueEx (phkResult [0], null, 0, null, lpData, lpcbData);
+ if (result == 0) {
+ String clsid = lpData.toString (0, lpData.strlen ());
+ if (clsid.equals (CLSID_SHELLEXPLORER1)) {
+ /* Shell.Explorer.1 is the default, ensure that Shell.Explorer.2 is available */
+ key = new TCHAR (0, "Shell.Explorer.2", true); //$NON-NLS-1$
+ int /*long*/ [] phkResult2 = new int /*long*/ [1];
+ if (OS.RegOpenKeyEx (OS.HKEY_CLASSES_ROOT, key, 0, OS.KEY_READ, phkResult2) == 0) {
+ /* specify that Shell.Explorer.2 is to be used */
+ OS.RegCloseKey (phkResult2 [0]);
+ ProgId = "Shell.Explorer.2"; //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ OS.RegCloseKey (phkResult [0]);
+ }
+ }
+
+public void create(Composite parent, int style) {
+ this.style = style;
+ frame = new OleFrame(browser, SWT.NONE);
+
+ try {
+ site = new WebSite(frame, SWT.NONE, ProgId); //$NON-NLS-1$
+ } catch (SWTException e) {
+ browser.dispose();
+ SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+
+ site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);
+ auto = new OleAutomation(site);
+
+ domListener = new OleListener() {
+ public void handleEvent (OleEvent e) {
+ handleDOMEvent(e);
+ }
+ };
+
+ Listener listener = new Listener() {
+ public void handleEvent(Event e) {
+ switch (e.type) {
+ case SWT.Dispose: {
+ /* make this handler run after other dispose listeners */
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (e.type, e);
+ e.type = SWT.NONE;
+
+ /*
+ * It is possible for the Browser's OLE frame to have been disposed
+ * by a Dispose listener that was invoked by notifyListeners above,
+ * so check for this before unhooking its DOM listeners.
+ */
+ if (!frame.isDisposed ()) unhookDOMListeners(documents);
+
+ for (int i = 0; i < documents.length; i++) {
+ documents[i].dispose();
+ }
+ documents = null;
+
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ ((BrowserFunction)elements.nextElement ()).dispose (false);
+ }
+ functions = null;
+
+ lastNavigateURL = null;
+ domListener = null;
+ if (auto != null) auto.dispose();
+ auto = null;
+ break;
+ }
+ case SWT.Resize: {
+ frame.setBounds(browser.getClientArea());
+ break;
+ }
+ case SWT.MouseWheel: {
+ /* MouseWheel events come from the DOM */
+ e.doit = false;
+ break;
+ }
+ /*
+ * FocusIn and Traverse are hooked to handle traversal into
+ * and out of the Browser when it has key listeners.
+ */
+ case SWT.FocusIn: {
+ site.setFocus();
+ break;
+ }
+ case SWT.Traverse: {
+ if (browser.isListening(SWT.KeyDown) || browser.isListening(SWT.KeyUp)) {
+ if (e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
+ browser.traverse(SWT.TRAVERSE_TAB_PREVIOUS);
+ e.doit = false;
+ }
+ }
+ break;
+ }
+ }
+ }
+ };
+ browser.addListener(SWT.Dispose, listener);
+ browser.addListener(SWT.FocusIn, listener);
+ browser.addListener(SWT.Resize, listener);
+ site.addListener(SWT.MouseWheel, listener);
+ site.addListener(SWT.Traverse, listener);
+
+ OleListener oleListener = new OleListener() {
+ public void handleEvent(OleEvent event) {
+ /* callbacks are asynchronous, auto could be disposed */
+ if (auto != null) {
+ switch (event.type) {
+ case BeforeNavigate2: {
+ Variant varResult = event.arguments[1];
+ String url = varResult.getString();
+ /*
+ * Bug in IE. For navigations on the local machine, BeforeNavigate2's url
+ * field contains a string representing the file path in a non-URL format.
+ * In order to be consistent with the other Browser implementations, this
+ * case is detected and the string is changed to be a proper url string.
+ */
+ if (url.indexOf(":/") == -1 && url.indexOf(":\\") != -1) { //$NON-NLS-1$ //$NON-NLS-2$
+ url = PROTOCOL_FILE + url.replace('\\', '/');
+ }
+ LocationEvent newEvent = new LocationEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.location = url;
+ newEvent.doit = true;
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changing(newEvent);
+ }
+ boolean doit = newEvent.doit && !browser.isDisposed();
+ Variant cancel = event.arguments[6];
+ if (cancel != null) {
+ int /*long*/ pCancel = cancel.getByRef();
+ COM.MoveMemory(pCancel, new short[] {doit ? COM.VARIANT_FALSE : COM.VARIANT_TRUE}, 2);
+ }
+ if (doit) {
+ lastNavigateURL = url;
+ varResult = event.arguments[0];
+ IDispatch dispatch = varResult.getDispatch();
+ Variant variant = new Variant(auto);
+ IDispatch top = variant.getDispatch();
+ boolean isTop = top.getAddress() == dispatch.getAddress();
+ if (isTop) {
+ /* unhook DOM listeners and unref the last document(s) */
+ unhookDOMListeners(documents);
+ for (int i = 0; i < documents.length; i++) {
+ documents[i].dispose();
+ }
+ documents = new OleAutomation[0];
+ }
+ }
+ break;
+ }
+ case CommandStateChange: {
+ boolean enabled = false;
+ Variant varResult = event.arguments[0];
+ int command = varResult.getInt();
+ varResult = event.arguments[1];
+ enabled = varResult.getBoolean();
+ switch (command) {
+ case CSC_NAVIGATEBACK : back = enabled; break;
+ case CSC_NAVIGATEFORWARD : forward = enabled; break;
+ }
+ break;
+ }
+ case DocumentComplete: {
+ Variant varResult = event.arguments[0];
+ IDispatch dispatch = varResult.getDispatch();
+
+ varResult = event.arguments[1];
+ String url = varResult.getString();
+ /*
+ * Bug in IE. For navigations on the local machine, DocumentComplete's URL
+ * field contains a string representing the file path in a non-URL format.
+ * In order to be consistent with the other Browser implementations, this
+ * case is detected and the string is changed to be a proper url string.
+ */
+ if (url.indexOf(":/") == -1 && url.indexOf(":\\") != -1) { //$NON-NLS-1$ //$NON-NLS-2$
+ url = PROTOCOL_FILE + url.replace('\\', '/');
+ }
+ if (html != null && url.equals(ABOUT_BLANK)) {
+ Runnable runnable = new Runnable () {
+ public void run() {
+ if (browser.isDisposed() || html == null) return;
+ int charCount = html.length();
+ char[] chars = new char[charCount];
+ html.getChars(0, charCount, chars, 0);
+ html = null;
+ int byteCount = OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, null, 0, null, null);
+ /*
+ * Note. Internet Explorer appears to treat the data loaded with
+ * nsIPersistStreamInit.Load as if it were encoded using the default
+ * local charset. There does not seem to be an API to set the
+ * desired charset explicitly in this case. The fix is to
+ * prepend the UTF-8 Byte Order Mark signature to the data.
+ */
+ byte[] UTF8BOM = {(byte)0xEF, (byte)0xBB, (byte)0xBF};
+ int /*long*/ hGlobal = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT, UTF8BOM.length + byteCount);
+ if (hGlobal != 0) {
+ OS.MoveMemory(hGlobal, UTF8BOM, UTF8BOM.length);
+ OS.WideCharToMultiByte(OS.CP_UTF8, 0, chars, charCount, hGlobal + UTF8BOM.length, byteCount, null, null);
+ int /*long*/ [] ppstm = new int /*long*/ [1];
+ /*
+ * Note. CreateStreamOnHGlobal is called with the flag fDeleteOnRelease.
+ * If the call succeeds the buffer hGlobal is freed automatically
+ * when the IStream object is released. If the call fails, free the buffer
+ * hGlobal.
+ */
+ if (OS.CreateStreamOnHGlobal(hGlobal, true, ppstm) == OS.S_OK) {
+ int[] rgdispid = auto.getIDsOfNames(new String[] {"Document"}); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ IDispatch dispatchDocument = pVarResult.getDispatch();
+ int /*long*/ [] ppvObject = new int /*long*/ [1];
+ int result = dispatchDocument.QueryInterface(COM.IIDIPersistStreamInit, ppvObject);
+ if (result == OS.S_OK) {
+ IPersistStreamInit persistStreamInit = new IPersistStreamInit(ppvObject[0]);
+ if (persistStreamInit.InitNew() == OS.S_OK) {
+ persistStreamInit.Load(ppstm[0]);
+ }
+ persistStreamInit.Release();
+ }
+ pVarResult.dispose();
+ /*
+ * This code is intentionally commented. The IDispatch obtained from a Variant
+ * did not increase the reference count for the enclosed interface.
+ */
+ //dispatchDocument.Release();
+ IUnknown stream = new IUnknown(ppstm[0]);
+ stream.Release();
+ } else {
+ OS.GlobalFree(hGlobal);
+ }
+ }
+ }
+ };
+ if (delaySetText) {
+ delaySetText = false;
+ browser.getDisplay().asyncExec(runnable);
+ } else {
+ runnable.run();
+ }
+ } else {
+ Variant variant = new Variant(auto);
+ IDispatch top = variant.getDispatch();
+ LocationEvent locationEvent = new LocationEvent(browser);
+ locationEvent.display = browser.getDisplay();
+ locationEvent.widget = browser;
+ locationEvent.location = url;
+ locationEvent.top = top.getAddress() == dispatch.getAddress();
+ for (int i = 0; i < locationListeners.length; i++) {
+ locationListeners[i].changed(locationEvent);
+ }
+ if (browser.isDisposed()) return;
+ /*
+ * This code is intentionally commented. A Variant constructed from an
+ * OleAutomation object does not increase its reference count. The IDispatch
+ * obtained from this Variant did not increase the reference count for the
+ * OleAutomation instance either.
+ */
+ //top.Release();
+ //variant.dispose();
+ /*
+ * Note. The completion of the page loading is detected as
+ * described in the MSDN article "Determine when a page is
+ * done loading in WebBrowser Control".
+ */
+ if (globalDispatch != 0 && dispatch.getAddress() == globalDispatch) {
+ /* final document complete */
+ globalDispatch = 0;
+
+ ProgressEvent progressEvent = new ProgressEvent(browser);
+ progressEvent.display = browser.getDisplay();
+ progressEvent.widget = browser;
+ for (int i = 0; i < progressListeners.length; i++) {
+ progressListeners[i].completed(progressEvent);
+ }
+ }
+ }
+
+ /*
+ * This code is intentionally commented. This IDispatch was received
+ * as an argument from the OleEvent and it will be disposed along with
+ * the other arguments.
+ */
+ //dispatch.Release();
+ break;
+ }
+ case NavigateComplete2: {
+ Variant varResult = event.arguments[0];
+ IDispatch dispatch = varResult.getDispatch();
+ if (globalDispatch == 0) globalDispatch = dispatch.getAddress();
+
+ OleAutomation webBrowser = varResult.getAutomation();
+ varResult = event.arguments[1];
+ Variant variant = new Variant(auto);
+ IDispatch top = variant.getDispatch();
+ boolean isTop = top.getAddress() == dispatch.getAddress();
+ if (isTop) {
+ /* re-install registered functions */
+ Enumeration elements = functions.elements ();
+ while (elements.hasMoreElements ()) {
+ BrowserFunction function = (BrowserFunction)elements.nextElement ();
+ execute (function.functionString);
+ }
+ }
+ hookDOMListeners(webBrowser, isTop);
+ webBrowser.dispose();
+ break;
+ }
+ case NewWindow2: {
+ Variant cancel = event.arguments[1];
+ int /*long*/ pCancel = cancel.getByRef();
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.required = false;
+ for (int i = 0; i < openWindowListeners.length; i++) {
+ openWindowListeners[i].open(newEvent);
+ }
+ IE browser = null;
+ if (newEvent.browser != null && newEvent.browser.webBrowser instanceof IE) {
+ browser = (IE)newEvent.browser.webBrowser;
+ }
+ boolean doit = browser != null && !browser.browser.isDisposed();
+ if (doit) {
+ Variant variant = new Variant(browser.auto);
+ IDispatch iDispatch = variant.getDispatch();
+ Variant ppDisp = event.arguments[0];
+ int /*long*/ byref = ppDisp.getByRef();
+ if (byref != 0) COM.MoveMemory(byref, new int /*long*/[] {iDispatch.getAddress()}, OS.PTR_SIZEOF);
+ /*
+ * This code is intentionally commented. A Variant constructed from an
+ * OleAutomation object does not increase its reference count. The IDispatch
+ * obtained from this Variant did not increase the reference count for the
+ * OleAutomation instance either.
+ */
+ //variant.dispose();
+ //iDispatch.Release();
+ }
+ if (newEvent.required) {
+ COM.MoveMemory(pCancel, new short[]{doit ? COM.VARIANT_FALSE : COM.VARIANT_TRUE}, 2);
+ }
+ break;
+ }
+ case OnMenuBar: {
+ Variant arg0 = event.arguments[0];
+ menuBar = arg0.getBoolean();
+ break;
+ }
+ case OnStatusBar: {
+ Variant arg0 = event.arguments[0];
+ statusBar = arg0.getBoolean();
+ break;
+ }
+ case OnToolBar: {
+ Variant arg0 = event.arguments[0];
+ toolBar = arg0.getBoolean();
+ /*
+ * Feature in Internet Explorer. OnToolBar FALSE is emitted
+ * when both tool bar, address bar and menu bar must not be visible.
+ * OnToolBar TRUE is emitted when either of tool bar, address bar
+ * or menu bar is visible.
+ */
+ if (!toolBar) {
+ addressBar = false;
+ menuBar = false;
+ }
+ break;
+ }
+ case OnVisible: {
+ Variant arg1 = event.arguments[0];
+ boolean visible = arg1.getBoolean();
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ if (visible) {
+ if (addressBar) {
+ /*
+ * Bug in Internet Explorer. There is no distinct notification for
+ * the address bar. If neither address, menu or tool bars are visible,
+ * OnToolBar FALSE is emitted. For some reason, querying the value of
+ * AddressBar in this case returns true even though it should not be
+ * set visible. The workaround is to only query the value of AddressBar
+ * when OnToolBar FALSE has not been emitted.
+ */
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "AddressBar" }); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ if (pVarResult != null) {
+ if (pVarResult.getType () == OLE.VT_BOOL) {
+ addressBar = pVarResult.getBoolean ();
+ }
+ pVarResult.dispose ();
+ }
+ }
+ newEvent.addressBar = addressBar;
+ newEvent.menuBar = menuBar;
+ newEvent.statusBar = statusBar;
+ newEvent.toolBar = toolBar;
+ newEvent.location = location;
+ newEvent.size = size;
+ for (int i = 0; i < visibilityWindowListeners.length; i++) {
+ visibilityWindowListeners[i].show(newEvent);
+ }
+ location = null;
+ size = null;
+ } else {
+ for (int i = 0; i < visibilityWindowListeners.length; i++) {
+ visibilityWindowListeners[i].hide(newEvent);
+ }
+ }
+ break;
+ }
+ case ProgressChange: {
+ Variant arg1 = event.arguments[0];
+ int nProgress = arg1.getType() != OLE.VT_I4 ? 0 : arg1.getInt(); // may be -1
+ Variant arg2 = event.arguments[1];
+ int nProgressMax = arg2.getType() != OLE.VT_I4 ? 0 : arg2.getInt();
+ ProgressEvent newEvent = new ProgressEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.current = nProgress;
+ newEvent.total = nProgressMax;
+ if (nProgress != -1) {
+ for (int i = 0; i < progressListeners.length; i++) {
+ progressListeners[i].changed(newEvent);
+ }
+ }
+ break;
+ }
+ case StatusTextChange: {
+ Variant arg1 = event.arguments[0];
+ if (arg1.getType() == OLE.VT_BSTR) {
+ String text = arg1.getString();
+ StatusTextEvent newEvent = new StatusTextEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.text = text;
+ for (int i = 0; i < statusTextListeners.length; i++) {
+ statusTextListeners[i].changed(newEvent);
+ }
+ }
+ break;
+ }
+ case TitleChange: {
+ Variant arg1 = event.arguments[0];
+ if (arg1.getType() == OLE.VT_BSTR) {
+ String title = arg1.getString();
+ TitleEvent newEvent = new TitleEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ newEvent.title = title;
+ for (int i = 0; i < titleListeners.length; i++) {
+ titleListeners[i].changed(newEvent);
+ }
+ }
+ break;
+ }
+ case WindowClosing: {
+ /*
+ * Disposing the Browser directly from this callback will crash if the
+ * Browser has a text field with an active caret. As a workaround fire
+ * the Close event and dispose the Browser in an async block.
+ */
+ browser.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (browser.isDisposed()) return;
+ WindowEvent newEvent = new WindowEvent(browser);
+ newEvent.display = browser.getDisplay();
+ newEvent.widget = browser;
+ for (int i = 0; i < closeWindowListeners.length; i++) {
+ closeWindowListeners[i].close(newEvent);
+ }
+ browser.dispose();
+ }
+ });
+ Variant cancel = event.arguments[1];
+ int /*long*/ pCancel = cancel.getByRef();
+ Variant arg1 = event.arguments[0];
+ boolean isChildWindow = arg1.getBoolean();
+ COM.MoveMemory(pCancel, new short[]{isChildWindow ? COM.VARIANT_FALSE : COM.VARIANT_TRUE}, 2);
+ break;
+ }
+ case WindowSetHeight: {
+ if (size == null) size = new Point(0, 0);
+ Variant arg1 = event.arguments[0];
+ size.y = arg1.getInt();
+ break;
+ }
+ case WindowSetLeft: {
+ if (location == null) location = new Point(0, 0);
+ Variant arg1 = event.arguments[0];
+ location.x = arg1.getInt();
+ break;
+ }
+ case WindowSetTop: {
+ if (location == null) location = new Point(0, 0);
+ Variant arg1 = event.arguments[0];
+ location.y = arg1.getInt();
+ break;
+ }
+ case WindowSetWidth: {
+ if (size == null) size = new Point(0, 0);
+ Variant arg1 = event.arguments[0];
+ size.x = arg1.getInt();
+ break;
+ }
+ }
+ }
+ /*
+ * Dispose all arguments passed in the OleEvent. This must be
+ * done to properly release any IDispatch reference that was
+ * automatically addRef'ed when constructing the OleEvent.
+ */
+ Variant[] arguments = event.arguments;
+ for (int i = 0; i < arguments.length; i++) arguments[i].dispose();
+ }
+ };
+ site.addEventListener(BeforeNavigate2, oleListener);
+ site.addEventListener(CommandStateChange, oleListener);
+ site.addEventListener(DocumentComplete, oleListener);
+ site.addEventListener(NavigateComplete2, oleListener);
+ site.addEventListener(NewWindow2, oleListener);
+ site.addEventListener(OnMenuBar, oleListener);
+ site.addEventListener(OnStatusBar, oleListener);
+ site.addEventListener(OnToolBar, oleListener);
+ site.addEventListener(OnVisible, oleListener);
+ site.addEventListener(ProgressChange, oleListener);
+ site.addEventListener(StatusTextChange, oleListener);
+ site.addEventListener(TitleChange, oleListener);
+ site.addEventListener(WindowClosing, oleListener);
+ site.addEventListener(WindowSetHeight, oleListener);
+ site.addEventListener(WindowSetLeft, oleListener);
+ site.addEventListener(WindowSetTop, oleListener);
+ site.addEventListener(WindowSetWidth, oleListener);
+
+ Variant variant = new Variant(true);
+ auto.setProperty(RegisterAsBrowser, variant);
+ variant.dispose();
+
+ variant = new Variant(false);
+ int[] rgdispid = auto.getIDsOfNames(new String[] {"RegisterAsDropTarget"}); //$NON-NLS-1$
+ if (rgdispid != null) auto.setProperty(rgdispid[0], variant);
+ variant.dispose();
+}
+
+public boolean back() {
+ if (!back) return false;
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "GoBack" }); //$NON-NLS-1$
+ Variant pVarResult = auto.invoke(rgdispid[0]);
+ return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
+}
+
+public boolean execute(String script) {
+ /* get IHTMLDocument2 */
+ int[] rgdispid = auto.getIDsOfNames(new String[]{"Document"}); //$NON-NLS-1$
+ int dispIdMember = rgdispid[0];
+ Variant pVarResult = auto.getProperty(dispIdMember);
+ if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
+ if (pVarResult != null) pVarResult.dispose ();
+ return false;
+ }
+ OleAutomation document = pVarResult.getAutomation();
+ pVarResult.dispose();
+
+ /* get IHTMLWindow2 */
+ rgdispid = document.getIDsOfNames(new String[]{"parentWindow"}); //$NON-NLS-1$
+ if (rgdispid == null) {
+ /* implies that browser's content is not a IHTMLDocument2 (eg.- acrobat reader) */
+ document.dispose();
+ return false;
+ }
+ dispIdMember = rgdispid[0];
+ pVarResult = document.getProperty(dispIdMember);
+ OleAutomation ihtmlWindow2 = pVarResult.getAutomation();
+ pVarResult.dispose();
+ document.dispose();
+
+ rgdispid = ihtmlWindow2.getIDsOfNames(new String[] { "execScript", "code" }); //$NON-NLS-1$ //$NON-NLS-2$
+ Variant[] rgvarg = new Variant[1];
+ rgvarg[0] = new Variant(script);
+ int[] rgdispidNamedArgs = new int[1];
+ rgdispidNamedArgs[0] = rgdispid[1];
+ pVarResult = ihtmlWindow2.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+ rgvarg[0].dispose();
+ ihtmlWindow2.dispose();
+ if (pVarResult == null) return false;
+ pVarResult.dispose();
+ return true;
+}
+
+public boolean forward() {
+ if (!forward) return false;
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "GoForward" }); //$NON-NLS-1$
+ Variant pVarResult = auto.invoke(rgdispid[0]);
+ return pVarResult != null && pVarResult.getType() == OLE.VT_EMPTY;
+}
+
+public String getBrowserType () {
+ return "ie"; //$NON-NLS-1$
+}
+
+String getDeleteFunctionString (String functionName) {
+ return "window." + functionName + "=undefined"; //$NON-NLS-1$ //$NON-NLS-2$
+}
+
+public String getText() {
+ /* get the document object */
+ int[] rgdispid = auto.getIDsOfNames(new String[]{"Document"}); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
+ if (pVarResult != null) pVarResult.dispose ();
+ return ""; //$NON-NLS-1$
+ }
+ OleAutomation document = pVarResult.getAutomation();
+ pVarResult.dispose();
+
+ /* get the html object */
+ rgdispid = document.getIDsOfNames(new String[] {"documentElement"}); //$NON-NLS-1$
+ if (rgdispid == null) {
+ /* implies that the browser is displaying non-HTML content */
+ document.dispose();
+ return ""; //$NON-NLS-1$
+ }
+ pVarResult = document.getProperty(rgdispid[0]);
+ document.dispose();
+ if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
+ if (pVarResult != null) pVarResult.dispose ();
+ return ""; //$NON-NLS-1$
+ }
+ OleAutomation element = pVarResult.getAutomation();
+ pVarResult.dispose();
+
+ /* get its outerHTML property */
+ rgdispid = element.getIDsOfNames(new String[] {"outerHTML"}); //$NON-NLS-1$
+ pVarResult = element.getProperty(rgdispid[0]);
+ element.dispose();
+ if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) {
+ if (pVarResult != null) pVarResult.dispose ();
+ return ""; //$NON-NLS-1$
+ }
+ String result = pVarResult.getString();
+ pVarResult.dispose();
+
+ return result;
+}
+
+public String getUrl() {
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "LocationURL" }); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ if (pVarResult == null || pVarResult.getType() != OLE.VT_BSTR) return ""; //$NON-NLS-1$
+ String result = pVarResult.getString();
+ pVarResult.dispose();
+ return result;
+}
+
+public boolean isBackEnabled() {
+ return back;
+}
+
+public boolean isForwardEnabled() {
+ return forward;
+}
+
+public boolean isFocusControl () {
+ return site.isFocusControl() || frame.isFocusControl();
+}
+
+public void refresh() {
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "Refresh" }); //$NON-NLS-1$
+ auto.invoke(rgdispid[0]);
+}
+
+public boolean setText(String html) {
+ /*
+ * If the html field is non-null then the about:blank page is already being
+ * loaded, so no Stop or Navigate is required. Just set the html that is to
+ * be shown.
+ */
+ boolean blankLoading = this.html != null;
+ this.html = html;
+ if (blankLoading) return true;
+
+ /*
+ * Navigate to the blank page and insert the given html when
+ * receiving the next DocumentComplete notification. See the
+ * MSDN article "Loading HTML content from a Stream".
+ *
+ * Note. Stop any pending request. This is required to avoid displaying a
+ * blank page as a result of consecutive calls to setUrl and/or setText.
+ * The previous request would otherwise render the new html content and
+ * reset the html field before the browser actually navigates to the blank
+ * page as requested below.
+ *
+ * Feature in Internet Explorer. Stopping pending requests when no request
+ * is pending causes a default page 'Action cancelled' to be displayed. The
+ * workaround is to not invoke 'stop' when no request has been set since
+ * that instance was created.
+ */
+ int[] rgdispid;
+ if (navigate) {
+ /*
+ * Stopping the loading of a page causes DocumentComplete events from previous
+ * requests to be received before the DocumentComplete for this page. In such
+ * cases we must be sure to not set the html into the browser too soon, since
+ * doing so could result in its page being cleared out by a subsequent
+ * DocumentComplete. The Browser's ReadyState can be used to determine whether
+ * these extra events will be received or not.
+ */
+ rgdispid = auto.getIDsOfNames(new String[] { "ReadyState" }); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ if (pVarResult == null) return false;
+ delaySetText = pVarResult.getInt() != READYSTATE_COMPLETE;
+ pVarResult.dispose();
+ rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
+ auto.invoke(rgdispid[0]);
+ }
+ rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
+ navigate = true;
+ Variant[] rgvarg = new Variant[1];
+ rgvarg[0] = new Variant(ABOUT_BLANK);
+ int[] rgdispidNamedArgs = new int[1];
+ rgdispidNamedArgs[0] = rgdispid[1];
+ boolean oldValue = false;
+ if (!OS.IsWinCE && IsIE7) {
+ int hResult = OS.CoInternetIsFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.GET_FEATURE_FROM_PROCESS);
+ oldValue = hResult == COM.S_OK;
+ OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
+ }
+ Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+ if (!OS.IsWinCE && IsIE7) {
+ OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, oldValue);
+ }
+ rgvarg[0].dispose();
+ if (pVarResult == null) return false;
+ boolean result = pVarResult.getType() == OLE.VT_EMPTY;
+ pVarResult.dispose();
+ return result;
+}
+
+public boolean setUrl(String url) {
+ html = null;
+
+ /*
+ * Bug in Internet Explorer. For some reason, Navigating to an xml document before
+ * a previous Navigate has completed will leave the Browser in a bad state if the
+ * Navigate to the xml document does not complete. This bad state causes a GP when
+ * the parent window is eventually disposed. The workaround is to issue a Stop before
+ * navigating to any xml document.
+ */
+ if (url.endsWith(".xml")) { //$NON-NLS-1$
+ /*
+ * Feature in Internet Explorer. Stopping pending requests when no request has been
+ * issued causes a default 'Action cancelled' page to be displayed. Since Stop must
+ * be issued here, the workaround is to first Navigate to the about:blank page before
+ * issuing Stop so that the 'Action cancelled' page is not displayed.
+ */
+ if (!navigate) {
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
+ Variant[] rgvarg = new Variant[1];
+ rgvarg[0] = new Variant(ABOUT_BLANK);
+ int[] rgdispidNamedArgs = new int[1];
+ rgdispidNamedArgs[0] = rgdispid[1];
+ boolean oldValue = false;
+ if (!OS.IsWinCE && IsIE7) {
+ int hResult = OS.CoInternetIsFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.GET_FEATURE_FROM_PROCESS);
+ oldValue = hResult == COM.S_OK;
+ OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, true);
+ }
+ auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+ if (!OS.IsWinCE && IsIE7) {
+ OS.CoInternetSetFeatureEnabled(OS.FEATURE_DISABLE_NAVIGATION_SOUNDS, OS.SET_FEATURE_ON_PROCESS, oldValue);
+ }
+ rgvarg[0].dispose();
+ }
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
+ auto.invoke(rgdispid[0]);
+ }
+
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
+ navigate = true;
+ Variant[] rgvarg = new Variant[1];
+ rgvarg[0] = new Variant(url);
+ int[] rgdispidNamedArgs = new int[1];
+ rgdispidNamedArgs[0] = rgdispid[1];
+ Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+ rgvarg[0].dispose();
+ if (pVarResult == null) return false;
+ boolean result = pVarResult.getType() == OLE.VT_EMPTY;
+ pVarResult.dispose();
+ return result;
+}
+
+public void stop() {
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
+ auto.invoke(rgdispid[0]);
+}
+
+void handleDOMEvent (OleEvent e) {
+ if (e.arguments == null || e.arguments.length == 0) return; /* for IE5 */
+
+ Variant arg = e.arguments[0];
+ OleAutomation event = arg.getAutomation();
+ int[] rgdispid = event.getIDsOfNames(new String[]{ PROPERTY_TYPE });
+ int dispIdMember = rgdispid[0];
+ Variant pVarResult = event.getProperty(dispIdMember);
+ String eventType = pVarResult.getString();
+ pVarResult.dispose();
+
+ if (eventType.equals(EVENT_KEYDOWN)) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ lastKeyCode = translateKey (pVarResult.getInt());
+ pVarResult.dispose();
+
+ MSG msg = new MSG ();
+ int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD;
+ if (OS.PeekMessage (msg, frame.handle, OS.WM_CHAR, OS.WM_CHAR, flags)) {
+ /* a keypress will be received for this key so don't send KeyDown here */
+ event.dispose();
+ return;
+ }
+
+ /* if this is a repeating key then an event should not be fired for it */
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_REPEAT });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ boolean repeating = pVarResult.getBoolean();
+ pVarResult.dispose();
+ if (repeating) {
+ event.dispose();
+ return;
+ }
+
+ int mask = 0;
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.ALT;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.CTRL;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
+ pVarResult.dispose();
+
+ Event keyEvent = new Event ();
+ keyEvent.widget = browser;
+ keyEvent.type = SWT.KeyDown;
+ keyEvent.keyCode = lastKeyCode;
+ keyEvent.stateMask = mask;
+ keyEvent.stateMask &= ~lastKeyCode; /* remove current keydown if it's a state key */
+ /*
+ * keypress events are not received for Enter, Delete and Tab, so
+ * KeyDown events are sent for them here. Set the KeyDown event's
+ * character field and IE's lastCharCode field for these keys so
+ * that the Browser's key events are consistent with other controls.
+ */
+ switch (lastKeyCode) {
+ case SWT.CR: lastCharCode = keyEvent.character = SWT.CR; break;
+ case SWT.DEL: lastCharCode = keyEvent.character = SWT.DEL; break;
+ case SWT.TAB: lastCharCode = keyEvent.character = SWT.TAB; break;
+ }
+ browser.notifyListeners (keyEvent.type, keyEvent);
+ if (!keyEvent.doit) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
+ dispIdMember = rgdispid[0];
+ Variant pVarFalse = new Variant(false);
+ event.setProperty(dispIdMember, pVarFalse);
+ pVarFalse.dispose();
+ }
+
+ event.dispose();
+ return;
+ }
+
+ if (eventType.equals(EVENT_KEYPRESS)) {
+ int mask = 0;
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.CTRL;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.ALT;
+ pVarResult.dispose();
+
+ /* in the keypress event the keyCode actually corresponds to the character code */
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ lastCharCode = pVarResult.getInt();
+ pVarResult.dispose();
+
+ /*
+ * WebSite.TranslateAccelerator() explicitly does not translate OS.VK_RETURN
+ * keys, so the PeekMessage check in the keydown handler always allows a
+ * KeyDown to be sent for this key. However, keydown and keypress events are
+ * both sometimes received for OS.VK_RETURN, depending on the page's focus
+ * control. To handle this, do not send a KeyDown for OS.VK_RETURN here since
+ * one is always sent for it from the keydown handler.
+ */
+ if (lastCharCode == OS.VK_RETURN) {
+ event.dispose();
+ return;
+ }
+
+ Event keyEvent = new Event ();
+ keyEvent.widget = browser;
+ keyEvent.type = SWT.KeyDown;
+ keyEvent.keyCode = lastKeyCode;
+ keyEvent.character = (char)lastCharCode;
+ keyEvent.stateMask = mask;
+ browser.notifyListeners (keyEvent.type, keyEvent);
+ if (!keyEvent.doit) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
+ dispIdMember = rgdispid[0];
+ Variant pVarFalse = new Variant(false);
+ event.setProperty(dispIdMember, pVarFalse);
+ pVarFalse.dispose();
+ }
+
+ event.dispose();
+ return;
+ }
+
+ if (eventType.equals(EVENT_KEYUP)) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_KEYCODE });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ int keyCode = translateKey (pVarResult.getInt());
+ pVarResult.dispose();
+
+ /*
+ * if a key code could not be determined for this key then it's a
+ * key for which key events are not sent (eg.- the Windows key)
+ */
+ if (keyCode == 0) {
+ lastKeyCode = lastCharCode = 0;
+ event.dispose();
+ return;
+ }
+
+ if (keyCode != lastKeyCode) {
+ /* keyup does not correspond to the last keydown */
+ lastKeyCode = keyCode;
+ lastCharCode = 0;
+ }
+
+ int mask = 0;
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.CTRL;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.ALT;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
+ pVarResult.dispose();
+
+ Event keyEvent = new Event ();
+ keyEvent.widget = browser;
+ keyEvent.type = SWT.KeyUp;
+ keyEvent.keyCode = lastKeyCode;
+ keyEvent.character = (char)lastCharCode;
+ keyEvent.stateMask = mask;
+ switch (lastKeyCode) {
+ case SWT.SHIFT:
+ case SWT.CONTROL:
+ case SWT.ALT:
+ case SWT.COMMAND: {
+ keyEvent.stateMask |= lastKeyCode;
+ }
+ }
+ browser.notifyListeners (keyEvent.type, keyEvent);
+ if (!keyEvent.doit) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_RETURNVALUE });
+ dispIdMember = rgdispid[0];
+ Variant pVarFalse = new Variant(false);
+ event.setProperty(dispIdMember, pVarFalse);
+ pVarFalse.dispose();
+ }
+
+ lastKeyCode = lastCharCode = 0;
+ event.dispose();
+ return;
+ }
+
+ /*
+ * Feature in IE. MouseOver/MouseOut events are fired any time the mouse enters
+ * or exits any element within the Browser. To ensure that SWT events are only
+ * fired for mouse movements into or out of the Browser, do not fire an event if
+ * the element being exited (on MouseOver) or entered (on MouseExit) is within
+ * the Browser.
+ */
+ if (eventType.equals(EVENT_MOUSEOVER)) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_FROMELEMENT });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ boolean isInternal = pVarResult.getType() != COM.VT_EMPTY;
+ pVarResult.dispose();
+ if (isInternal) {
+ event.dispose();
+ return;
+ }
+ }
+ if (eventType.equals(EVENT_MOUSEOUT)) {
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_TOELEMENT });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ boolean isInternal = pVarResult.getType() != COM.VT_EMPTY;
+ pVarResult.dispose();
+ if (isInternal) {
+ event.dispose();
+ return;
+ }
+ }
+
+ int x, y, mask = 0;
+ Event newEvent = new Event();
+ newEvent.widget = browser;
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CLIENTX });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ x = pVarResult.getInt();
+ newEvent.x = x;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CLIENTY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ y = pVarResult.getInt();
+ newEvent.y = y;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_CTRLKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.CTRL;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_ALTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.ALT;
+ pVarResult.dispose();
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_SHIFTKEY });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ if (pVarResult.getBoolean()) mask |= SWT.SHIFT;
+ pVarResult.dispose();
+
+ newEvent.stateMask = mask;
+
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_BUTTON });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ int button = pVarResult.getInt();
+ pVarResult.dispose();
+ switch (button) {
+ case 1: button = 1; break;
+ case 2: button = 3; break;
+ case 4: button = 2; break;
+ };
+
+ if (eventType.equals(EVENT_MOUSEDOWN)) {
+ newEvent.type = SWT.MouseDown;
+ newEvent.button = button;
+ newEvent.count = 1;
+ } else if (eventType.equals(EVENT_MOUSEUP) || eventType.equals(EVENT_DRAGEND)) {
+ newEvent.type = SWT.MouseUp;
+ newEvent.button = button != 0 ? button : 1; /* button assumed to be 1 for dragends */
+ newEvent.count = 1;
+ switch (newEvent.button) {
+ case 1: newEvent.stateMask |= SWT.BUTTON1; break;
+ case 2: newEvent.stateMask |= SWT.BUTTON2; break;
+ case 3: newEvent.stateMask |= SWT.BUTTON3; break;
+ case 4: newEvent.stateMask |= SWT.BUTTON4; break;
+ case 5: newEvent.stateMask |= SWT.BUTTON5; break;
+ }
+ } else if (eventType.equals(EVENT_MOUSEWHEEL)) {
+ newEvent.type = SWT.MouseWheel;
+ rgdispid = event.getIDsOfNames(new String[] { PROPERTY_WHEELDELTA });
+ dispIdMember = rgdispid[0];
+ pVarResult = event.getProperty(dispIdMember);
+ newEvent.count = pVarResult.getInt () / 120 * 3;
+ pVarResult.dispose();
+ } else if (eventType.equals(EVENT_MOUSEMOVE)) {
+ /*
+ * Feature in IE. Spurious and redundant mousemove events are often received. The workaround
+ * is to not fire MouseMove events whose x and y values match the last MouseMove.
+ */
+ if (newEvent.x == lastMouseMoveX && newEvent.y == lastMouseMoveY) return;
+ newEvent.type = SWT.MouseMove;
+ lastMouseMoveX = newEvent.x; lastMouseMoveY = newEvent.y;
+ } else if (eventType.equals(EVENT_MOUSEOVER)) {
+ newEvent.type = SWT.MouseEnter;
+ } else if (eventType.equals(EVENT_MOUSEOUT)) {
+ newEvent.type = SWT.MouseExit;
+ } else if (eventType.equals(EVENT_DRAGSTART)) {
+ newEvent.type = SWT.DragDetect;
+ newEvent.button = 1; /* button assumed to be 1 for dragstarts */
+ newEvent.stateMask |= SWT.BUTTON1;
+ }
+
+ event.dispose();
+ browser.notifyListeners(newEvent.type, newEvent);
+
+ if (eventType.equals(EVENT_DOUBLECLICK)) {
+ newEvent = new Event ();
+ newEvent.widget = browser;
+ newEvent.type = SWT.MouseDoubleClick;
+ newEvent.x = x; newEvent.y = y;
+ newEvent.stateMask = mask;
+ newEvent.type = SWT.MouseDoubleClick;
+ newEvent.button = 1; /* dblclick only comes for button 1 and does not set the button property */
+ newEvent.count = 2;
+ browser.notifyListeners (newEvent.type, newEvent);
+ }
+}
+
+void hookDOMListeners(OleAutomation webBrowser, final boolean isTop) {
+ int[] rgdispid = webBrowser.getIDsOfNames(new String[]{ "Document" }); //$NON-NLS-1$
+ int dispIdMember = rgdispid[0];
+ Variant pVarResult = webBrowser.getProperty(dispIdMember);
+ if (pVarResult == null) return;
+ if (pVarResult.getType() == COM.VT_EMPTY) {
+ pVarResult.dispose();
+ return;
+ }
+ final OleAutomation document = pVarResult.getAutomation();
+ pVarResult.dispose();
+
+ /*
+ * In some cases, such as setting the Browser's content from a string,
+ * NavigateComplete2 is received multiple times for a top-level document.
+ * For cases like this, any previously-hooked DOM listeners must be
+ * removed from the document before hooking the new set of listeners,
+ * otherwise multiple sets of events will be received.
+ */
+ unhookDOMListeners (new OleAutomation[] {document});
+
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYUP, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEWHEEL, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGEND, domListener);
+ /* ensure that enter/exit are only fired once, by the top-level document */
+ if (isTop) {
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER, domListener);
+ site.addEventListener(document, COM.IIDIHTMLDocumentEvents2, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT, domListener);
+ }
+
+ OleAutomation[] newDocuments = new OleAutomation[documents.length + 1];
+ System.arraycopy(documents, 0, newDocuments, 0, documents.length);
+ newDocuments[documents.length] = document;
+ documents = newDocuments;
+}
+
+void unhookDOMListeners(OleAutomation[] documents) {
+ char[] buffer = (COM.IIDIHTMLDocumentEvents2 + '\0').toCharArray();
+ GUID guid = new GUID();
+ if (COM.IIDFromString(buffer, guid) == COM.S_OK) {
+ for (int i = 0; i < documents.length; i++) {
+ OleAutomation document = documents[i];
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYDOWN, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYPRESS, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONKEYUP, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEDOWN, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEUP, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEWHEEL, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDBLCLICK, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEMOVE, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGSTART, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONDRAGEND, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOVER, domListener);
+ site.removeEventListener(document, guid, COM.DISPID_HTMLDOCUMENTEVENTS_ONMOUSEOUT, domListener);
+ }
+ }
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/WebSite.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/WebSite.java
new file mode 100644
index 0000000000..0c2bc056d7
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/WebSite.java
@@ -0,0 +1,921 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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 org.eclipse.swt.*;
+import org.eclipse.swt.internal.C;
+import org.eclipse.swt.internal.ole.win32.*;
+import org.eclipse.swt.ole.win32.*;
+import org.eclipse.swt.widgets.*;
+import org.eclipse.swt.internal.win32.*;
+
+class WebSite extends OleControlSite {
+ COMObject iDocHostUIHandler;
+ COMObject iDocHostShowUI;
+ COMObject iServiceProvider;
+ COMObject iInternetSecurityManager;
+ COMObject iOleCommandTarget;
+ COMObject iAuthenticate;
+ COMObject iDispatch;
+ boolean ignoreNextMessage;
+ Boolean canExecuteApplets;
+
+ static final int OLECMDID_SHOWSCRIPTERROR = 40;
+ static final short [] ACCENTS = new short [] {'~', '`', '\'', '^', '"'};
+ static final String CONSUME_KEY = "org.eclipse.swt.OleFrame.ConsumeKey"; //$NON-NLS-1$
+
+public WebSite(Composite parent, int style, String progId) {
+ super(parent, style, progId);
+}
+
+protected void createCOMInterfaces () {
+ super.createCOMInterfaces();
+ iDocHostUIHandler = new COMObject(new int[]{2, 0, 0, 4, 1, 5, 0, 0, 1, 1, 1, 3, 3, 2, 2, 1, 3, 2}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return ShowContextMenu((int)/*64*/args[0], args[1], args[2], args[3]);}
+ public int /*long*/ method4(int /*long*/[] args) {return GetHostInfo(args[0]);}
+ public int /*long*/ method5(int /*long*/[] args) {return ShowUI((int)/*64*/args[0], args[1], args[2], args[3], args[4]);}
+ public int /*long*/ method6(int /*long*/[] args) {return HideUI();}
+ public int /*long*/ method7(int /*long*/[] args) {return UpdateUI();}
+ public int /*long*/ method8(int /*long*/[] args) {return EnableModeless((int)/*64*/args[0]);}
+ public int /*long*/ method9(int /*long*/[] args) {return OnDocWindowActivate((int)/*64*/args[0]);}
+ public int /*long*/ method10(int /*long*/[] args) {return OnFrameWindowActivate((int)/*64*/args[0]);}
+ public int /*long*/ method11(int /*long*/[] args) {return ResizeBorder(args[0], args[1], (int)/*64*/args[2]);}
+ public int /*long*/ method12(int /*long*/[] args) {return TranslateAccelerator(args[0], args[1], (int)/*64*/args[2]);}
+ public int /*long*/ method13(int /*long*/[] args) {return GetOptionKeyPath(args[0], (int)/*64*/args[1]);}
+ public int /*long*/ method14(int /*long*/[] args) {return GetDropTarget(args[0], args[1]);}
+ public int /*long*/ method15(int /*long*/[] args) {return GetExternal(args[0]);}
+ public int /*long*/ method16(int /*long*/[] args) {return TranslateUrl((int)/*64*/args[0], args[1], args[2]);}
+ public int /*long*/ method17(int /*long*/[] args) {return FilterDataObject(args[0], args[1]);}
+ };
+ iDocHostShowUI = new COMObject(new int[]{2, 0, 0, 7, C.PTR_SIZEOF == 4 ? 7 : 6}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return ShowMessage(args[0], args[1], args[2], (int)/*64*/args[3], args[4], (int)/*64*/args[5], args[6]);}
+ public int /*long*/ method4(int /*long*/[] args) {
+ if (args.length == 7) {
+ return ShowHelp(args[0], args[1], (int)/*64*/args[2], (int)/*64*/args[3], (int)/*64*/args[4], (int)/*64*/args[5], args[6]);
+ } else {
+ return ShowHelp_64(args[0], args[1], (int)/*64*/args[2], (int)/*64*/args[3], args[4], args[5]);
+ }
+ }
+ };
+ iServiceProvider = new COMObject(new int[]{2, 0, 0, 3}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return QueryService(args[0], args[1], args[2]);}
+ };
+ iInternetSecurityManager = new COMObject(new int[]{2, 0, 0, 1, 1, 3, 4, 8, 7, 3, 3}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return SetSecuritySite(args[0]);}
+ public int /*long*/ method4(int /*long*/[] args) {return GetSecuritySite(args[0]);}
+ public int /*long*/ method5(int /*long*/[] args) {return MapUrlToZone(args[0], args[1], (int)/*64*/args[2]);}
+ public int /*long*/ method6(int /*long*/[] args) {return GetSecurityId(args[0], args[1], args[2], args[3]);}
+ public int /*long*/ method7(int /*long*/[] args) {return ProcessUrlAction(args[0], (int)/*64*/args[1], args[2], (int)/*64*/args[3], args[4], (int)/*64*/args[5], (int)/*64*/args[6], (int)/*64*/args[7]);}
+ public int /*long*/ method8(int /*long*/[] args) {return QueryCustomPolicy(args[0], args[1], args[2], args[3], args[4], (int)/*64*/args[5], (int)/*64*/args[6]);}
+ public int /*long*/ method9(int /*long*/[] args) {return SetZoneMapping((int)/*64*/args[0], args[1], (int)/*64*/args[2]);}
+ public int /*long*/ method10(int /*long*/[] args) {return GetZoneMappings((int)/*64*/args[0], args[1], (int)/*64*/args[2]);}
+ };
+ iOleCommandTarget = new COMObject(new int[]{2, 0, 0, 4, 5}) {
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return QueryStatus(args[0], (int)/*64*/args[1], args[2], args[3]);}
+ public int /*long*/ method4(int /*long*/[] args) {return Exec(args[0], (int)/*64*/args[1], (int)/*64*/args[2], args[3], args[4]);}
+ };
+ iAuthenticate = new COMObject(new int[]{2, 0, 0, 3}){
+ public int /*long*/ method0(int /*long*/[] args) {return QueryInterface(args[0], args[1]);}
+ public int /*long*/ method1(int /*long*/[] args) {return AddRef();}
+ public int /*long*/ method2(int /*long*/[] args) {return Release();}
+ public int /*long*/ method3(int /*long*/[] args) {return Authenticate(args[0], args[1], args[2]);}
+ };
+ iDispatch = new COMObject (new int[] {2, 0, 0, 1, 3, 5, 8}) {
+ public int /*long*/ method0 (int /*long*/[] args) {
+ /*
+ * IDispatch check must be done here instead of in the shared QueryInterface
+ * implementation, to avoid answering the superclass's IDispatch implementation
+ * instead of this one.
+ */
+ GUID guid = new GUID ();
+ COM.MoveMemory (guid, args[0], GUID.sizeof);
+ if (COM.IsEqualGUID (guid, COM.IIDIDispatch)) {
+ COM.MoveMemory (args[1], new int /*long*/[] {iDispatch.getAddress ()}, OS.PTR_SIZEOF);
+ AddRef ();
+ return COM.S_OK;
+ }
+ return QueryInterface (args[0], args[1]);
+ }
+ public int /*long*/ method1 (int /*long*/[] args) {return AddRef ();}
+ public int /*long*/ method2 (int /*long*/[] args) {return Release ();}
+ public int /*long*/ method3 (int /*long*/[] args) {return GetTypeInfoCount (args[0]);}
+ public int /*long*/ method4 (int /*long*/[] args) {return GetTypeInfo ((int)/*64*/args[0], (int)/*64*/args[1], args[2]);}
+ public int /*long*/ method5 (int /*long*/[] args) {return GetIDsOfNames ((int)/*64*/args[0], args[1], (int)/*64*/args[2], (int)/*64*/args[3], args[4]);}
+ public int /*long*/ method6 (int /*long*/[] args) {return Invoke ((int)/*64*/args[0], (int)/*64*/args[1], (int)/*64*/args[2], (int)/*64*/args[3], args[4], args[5], args[6], args[7]);}
+ };
+}
+
+protected void disposeCOMInterfaces() {
+ super.disposeCOMInterfaces();
+ if (iDocHostUIHandler != null) {
+ iDocHostUIHandler.dispose();
+ iDocHostUIHandler = null;
+ }
+ if (iDocHostShowUI != null) {
+ iDocHostShowUI.dispose();
+ iDocHostShowUI = null;
+ }
+ if (iServiceProvider != null) {
+ iServiceProvider.dispose();
+ iServiceProvider = null;
+ }
+ if (iInternetSecurityManager != null) {
+ iInternetSecurityManager.dispose();
+ iInternetSecurityManager = null;
+ }
+ if (iOleCommandTarget != null) {
+ iOleCommandTarget.dispose();
+ iOleCommandTarget = null;
+ }
+ if (iAuthenticate != null) {
+ iAuthenticate.dispose();
+ iAuthenticate = null;
+ }
+ if (iDispatch != null) {
+ iDispatch.dispose ();
+ iDispatch = null;
+ }
+}
+
+protected int AddRef() {
+ /* Workaround for javac 1.1.8 bug */
+ return super.AddRef();
+}
+
+protected int QueryInterface(int /*long*/ riid, int /*long*/ ppvObject) {
+ int result = super.QueryInterface(riid, ppvObject);
+ if (result == COM.S_OK) return result;
+ if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIDocHostUIHandler)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iDocHostUIHandler.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIDocHostShowUI)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iDocHostShowUI.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIServiceProvider)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iServiceProvider.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIInternetSecurityManager)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iInternetSecurityManager.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIOleCommandTarget)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iOleCommandTarget.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ COM.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+/* IDocHostUIHandler */
+
+int EnableModeless(int EnableModeless) {
+ return COM.E_NOTIMPL;
+}
+
+int FilterDataObject(int /*long*/ pDO, int /*long*/ ppDORet) {
+ return COM.E_NOTIMPL;
+}
+
+int GetDropTarget(int /*long*/ pDropTarget, int /*long*/ ppDropTarget) {
+ return COM.E_NOTIMPL;
+}
+
+int GetExternal(int /*long*/ ppDispatch) {
+ OS.MoveMemory (ppDispatch, new int /*long*/[] {iDispatch.getAddress()}, C.PTR_SIZEOF);
+ AddRef ();
+ return COM.S_OK;
+}
+
+int GetHostInfo(int /*long*/ pInfo) {
+ int info = IE.DOCHOSTUIFLAG_THEME;
+ IE browser = (IE)((Browser)getParent().getParent()).webBrowser;
+ if ((browser.style & SWT.BORDER) == 0) info |= IE.DOCHOSTUIFLAG_NO3DOUTERBORDER;
+ OS.MoveMemory(pInfo + 4, new int[] {info}, 4);
+
+ /*
+ * TODO replace the implementation above with the one commented below
+ * when 32-bit swt starts compiling with a newer mssdk whose definition
+ * of DOCHOSTUIINFO includes the last two OLECHAR* fields.
+ */
+// int info = IE.DOCHOSTUIFLAG_THEME;
+// Browser browser = (Browser)getParent().getParent();
+// if ((browser.getStyle() & SWT.BORDER) == 0) info |= IE.DOCHOSTUIFLAG_NO3DOUTERBORDER;
+//
+// DOCHOSTUIINFO uiInfo = new DOCHOSTUIINFO ();
+// OS.MoveMemory(uiInfo, pInfo, DOCHOSTUIINFO.sizeof);
+// uiInfo.dwFlags = info;
+// OS.MoveMemory(pInfo, uiInfo, DOCHOSTUIINFO.sizeof);
+ return COM.S_OK;
+}
+
+int GetOptionKeyPath(int /*long*/ pchKey, int dw) {
+ return COM.E_NOTIMPL;
+}
+
+int HideUI() {
+ return COM.E_NOTIMPL;
+}
+
+int OnDocWindowActivate(int fActivate) {
+ return COM.E_NOTIMPL;
+}
+
+int OnFrameWindowActivate(int fActivate) {
+ return COM.E_NOTIMPL;
+}
+
+protected int Release() {
+ /* Workaround for javac 1.1.8 bug */
+ return super.Release();
+}
+
+int ResizeBorder(int /*long*/ prcBorder, int /*long*/ pUIWindow, int fFrameWindow) {
+ return COM.E_NOTIMPL;
+}
+
+int ShowContextMenu(int dwID, int /*long*/ ppt, int /*long*/ pcmdtReserved, int /*long*/ pdispReserved) {
+ Browser browser = (Browser)getParent().getParent();
+ Event event = new Event();
+ POINT pt = new POINT();
+ OS.MoveMemory(pt, ppt, POINT.sizeof);
+ event.x = pt.x;
+ event.y = pt.y;
+ browser.notifyListeners(SWT.MenuDetect, event);
+ if (!event.doit) return COM.S_OK;
+ Menu menu = browser.getMenu();
+ if (menu != null && !menu.isDisposed ()) {
+ if (pt.x != event.x || pt.y != event.y) {
+ menu.setLocation (event.x, event.y);
+ }
+ menu.setVisible (true);
+ return COM.S_OK;
+ }
+ /* Show default IE popup menu */
+ return COM.S_FALSE;
+}
+
+int ShowUI(int dwID, int /*long*/ pActiveObject, int /*long*/ pCommandTarget, int /*long*/ pFrame, int /*long*/ pDoc) {
+ return COM.S_FALSE;
+}
+
+int TranslateAccelerator(int /*long*/ lpMsg, int /*long*/ pguidCmdGroup, int nCmdID) {
+ /*
+ * Feature on Internet Explorer. By default the embedded Internet Explorer control runs
+ * the Internet Explorer shortcuts (e.g. Ctrl+F for Find). This overrides the shortcuts
+ * defined by SWT. The workaround is to forward the accelerator keys to the parent window
+ * and have Internet Explorer ignore the ones handled by the parent window.
+ */
+ Menu menubar = getShell().getMenuBar();
+ if (menubar != null && !menubar.isDisposed() && menubar.isEnabled()) {
+ Shell shell = menubar.getShell();
+ int /*long*/ hwnd = shell.handle;
+ int /*long*/ hAccel = OS.SendMessage(hwnd, OS.WM_APP+1, 0, 0);
+ if (hAccel != 0) {
+ MSG msg = new MSG();
+ OS.MoveMemory(msg, lpMsg, MSG.sizeof);
+ if (OS.TranslateAccelerator(hwnd, hAccel, msg) != 0) return COM.S_OK;
+ }
+ }
+ /*
+ * By default the IE shortcuts are run. However, F5 causes a refresh, which is not
+ * appropriate when rendering HTML from memory, and CTRL-N opens a standalone IE,
+ * which is undesirable and can cause a crash in some contexts. The workaround is
+ * to block IE from handling these shortcuts by answering COM.S_OK.
+ */
+ int result = COM.S_FALSE;
+ MSG msg = new MSG();
+ OS.MoveMemory(msg, lpMsg, MSG.sizeof);
+ if (msg.message == OS.WM_KEYDOWN) {
+ switch ((int)/*64*/msg.wParam) {
+ case OS.VK_F5:
+ OleAutomation auto = new OleAutomation(this);
+ int[] rgdispid = auto.getIDsOfNames(new String[] { "LocationURL" }); //$NON-NLS-1$
+ Variant pVarResult = auto.getProperty(rgdispid[0]);
+ auto.dispose();
+ if (pVarResult != null) {
+ if (pVarResult.getType() == OLE.VT_BSTR) {
+ String url = pVarResult.getString();
+ if (url.equals(IE.ABOUT_BLANK)) result = COM.S_OK;
+ }
+ pVarResult.dispose();
+ }
+ break;
+ case OS.VK_TAB:
+ /*
+ * Do not interfere with tab traversal since it's not known
+ * if it will be within IE or out to another Control.
+ */
+ break;
+ case OS.VK_RETURN:
+ /*
+ * Translating OS.VK_RETURN results in the native control handling it
+ * twice (eg.- inserting two lines instead of one). So this key is not
+ * translated here, and instead is explicitly handled in the keypress
+ * handler.
+ */
+ break;
+ case OS.VK_N:
+ if (OS.GetKeyState (OS.VK_CONTROL) < 0 && OS.GetKeyState (OS.VK_MENU) >= 0 && OS.GetKeyState (OS.VK_SHIFT) >= 0) {
+ frame.setData(CONSUME_KEY, "false"); //$NON-NLS-1$
+ result = COM.S_OK;
+ break;
+ }
+ // FALL THROUGH
+ default:
+ OS.TranslateMessage(msg);
+ frame.setData(CONSUME_KEY, "true"); //$NON-NLS-1$
+ break;
+ }
+ }
+
+ switch (msg.message) {
+ case OS.WM_KEYDOWN:
+ case OS.WM_KEYUP: {
+ if (!OS.IsWinCE) {
+ boolean isAccent = false;
+ switch ((int)/*64*/msg.wParam) {
+ case OS.VK_SHIFT:
+ case OS.VK_MENU:
+ case OS.VK_CONTROL:
+ case OS.VK_CAPITAL:
+ case OS.VK_NUMLOCK:
+ case OS.VK_SCROLL:
+ break;
+ default: {
+ /*
+ * Bug in Windows. The high bit in the result of MapVirtualKey() on
+ * Windows NT is bit 32 while the high bit on Windows 95 is bit 16.
+ * They should both be bit 32. The fix is to test the right bit.
+ */
+ int mapKey = OS.MapVirtualKey ((int)/*64*/msg.wParam, 2);
+ if (mapKey != 0) {
+ isAccent = (mapKey & (OS.IsWinNT ? 0x80000000 : 0x8000)) != 0;
+ if (!isAccent) {
+ for (int i=0; i<ACCENTS.length; i++) {
+ int value = OS.VkKeyScan (ACCENTS [i]);
+ if (value != -1 && (value & 0xFF) == msg.wParam) {
+ int state = value >> 8;
+ if ((OS.GetKeyState (OS.VK_SHIFT) < 0) == ((state & 0x1) != 0) &&
+ (OS.GetKeyState (OS.VK_CONTROL) < 0) == ((state & 0x2) != 0) &&
+ (OS.GetKeyState (OS.VK_MENU) < 0) == ((state & 0x4) != 0)) {
+ if ((state & 0x7) != 0) isAccent = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ };
+ if (isAccent) result = COM.S_OK;
+ }
+ }
+ }
+ return result;
+}
+
+int TranslateUrl(int dwTranslate, int /*long*/ pchURLIn, int /*long*/ ppchURLOut) {
+ return COM.E_NOTIMPL;
+}
+
+int UpdateUI() {
+ return COM.E_NOTIMPL;
+}
+
+/* IDocHostShowUI */
+
+int ShowMessage(int /*long*/ hwnd, int /*long*/ lpstrText, int /*long*/ lpstrCaption, int dwType, int /*long*/ lpstrHelpFile, int dwHelpContext, int /*long*/ plResult) {
+ boolean ignore = ignoreNextMessage;
+ ignoreNextMessage = false;
+ return ignore ? COM.S_OK : COM.S_FALSE;
+}
+
+int ShowHelp_64(int /*long*/ hwnd, int /*long*/ pszHelpFile, int uCommand, int dwData, long pt, int /*long*/ pDispatchObjectHit) {
+ POINT point = new POINT();
+ OS.MoveMemory(point, new long[]{pt}, 8);
+ return ShowHelp(hwnd, pszHelpFile, uCommand, dwData, point.x, point.y, pDispatchObjectHit);
+}
+
+/* Note. One of the arguments of ShowHelp is a POINT struct and not a pointer to a POINT struct. Because
+ * of the way Callback gets int parameters from a va_list of C arguments 2 integer arguments must be declared,
+ * ptMouse_x and ptMouse_y. Otherwise the Browser crashes when the user presses F1 to invoke
+ * the help.
+ */
+int ShowHelp(int /*long*/ hwnd, int /*long*/ pszHelpFile, int uCommand, int dwData, int ptMouse_x, int ptMouse_y, int /*long*/ pDispatchObjectHit) {
+ Browser browser = (Browser)getParent().getParent();
+ Event event = new Event();
+ event.type = SWT.Help;
+ event.display = getDisplay();
+ event.widget = browser;
+ Shell shell = browser.getShell();
+ Control control = browser;
+ do {
+ if (control.isListening(SWT.Help)) {
+ control.notifyListeners(SWT.Help, event);
+ break;
+ }
+ if (control == shell) break;
+ control = control.getParent();
+ } while (true);
+ return COM.S_OK;
+}
+
+/* IServiceProvider */
+
+int QueryService(int /*long*/ guidService, int /*long*/ riid, int /*long*/ ppvObject) {
+ if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, riid, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDIInternetSecurityManager)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iInternetSecurityManager.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDIAuthenticate)) {
+ COM.MoveMemory(ppvObject, new int /*long*/[] {iAuthenticate.getAddress()}, OS.PTR_SIZEOF);
+ AddRef();
+ return COM.S_OK;
+ }
+ COM.MoveMemory(ppvObject, new int /*long*/[] {0}, OS.PTR_SIZEOF);
+ return COM.E_NOINTERFACE;
+}
+
+/* IInternetSecurityManager */
+
+int SetSecuritySite(int /*long*/ pSite) {
+ return IE.INET_E_DEFAULT_ACTION;
+}
+
+int GetSecuritySite(int /*long*/ ppSite) {
+ return IE.INET_E_DEFAULT_ACTION;
+}
+
+int MapUrlToZone(int /*long*/ pwszUrl, int /*long*/ pdwZone, int dwFlags) {
+ /*
+ * Feature in IE 6 sp1. HTML rendered in memory
+ * does not enable local links but the exact same
+ * HTML document loaded through a local file is
+ * permitted to follow local links. The workaround is
+ * to return URLZONE_INTRANET instead of the default
+ * value URLZONE_LOCAL_MACHINE.
+ */
+ COM.MoveMemory(pdwZone, new int[] {IE.URLZONE_INTRANET}, 4);
+ return COM.S_OK;
+}
+
+int GetSecurityId(int /*long*/ pwszUrl, int /*long*/ pbSecurityId, int /*long*/ pcbSecurityId, int /*long*/ dwReserved) {
+ return IE.INET_E_DEFAULT_ACTION;
+}
+
+int ProcessUrlAction(int /*long*/ pwszUrl, int dwAction, int /*long*/ pPolicy, int cbPolicy, int /*long*/ pContext, int cbContext, int dwFlags, int dwReserved) {
+ ignoreNextMessage = false;
+
+ /*
+ * Feature in IE 6 sp1. HTML rendered in memory
+ * containing an OBJECT tag referring to a local file
+ * brings up a warning dialog asking the user whether
+ * it should proceed or not. The workaround is to
+ * set the policy to URLPOLICY_ALLOW in this case (dwAction
+ * value of 0x1406).
+ *
+ * Feature in IE. Security Patches and user settings
+ * affect the way the embedded web control behaves. The current
+ * approach is to consider the content trusted and allow
+ * all URLs by default.
+ */
+ int policy = IE.URLPOLICY_ALLOW;
+
+ if (dwAction >= IE.URLACTION_JAVA_MIN && dwAction <= IE.URLACTION_JAVA_MAX) {
+ if (canExecuteApplets ()) {
+ policy = IE.URLPOLICY_JAVA_LOW;
+ } else {
+ policy = IE.URLPOLICY_JAVA_PROHIBIT;
+ ignoreNextMessage = true;
+ }
+ }
+ if (dwAction == IE.URLACTION_ACTIVEX_RUN) {
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, pContext, GUID.sizeof);
+ if (COM.IsEqualGUID(guid, COM.IIDJavaBeansBridge) && !canExecuteApplets ()) {
+ policy = IE.URLPOLICY_DISALLOW;
+ ignoreNextMessage = true;
+ }
+ if (COM.IsEqualGUID(guid, COM.IIDShockwaveActiveXControl)) {
+ policy = IE.URLPOLICY_DISALLOW;
+ ignoreNextMessage = true;
+ }
+ }
+ if (dwAction == IE.URLACTION_SCRIPT_RUN) {
+ IE browser = (IE)((Browser)getParent ().getParent ()).webBrowser;
+ if (!browser.jsEnabled) {
+ policy = IE.URLPOLICY_DISALLOW;
+ }
+ }
+
+ if (cbPolicy >= 4) COM.MoveMemory(pPolicy, new int[] {policy}, 4);
+ return policy == IE.URLPOLICY_ALLOW ? COM.S_OK : COM.S_FALSE;
+}
+
+boolean canExecuteApplets () {
+ /*
+ * Executing an applet in embedded IE will crash if IE's Java plug-in
+ * launches its jre in IE's process, because this new jre conflicts
+ * with the one running eclipse. These cases need to be avoided by
+ * vetoing the running of applets.
+ *
+ * However as of Sun jre 1.6u10, applets can be launched in a separate
+ * process, which avoids the conflict with the jre running eclipse.
+ * Therefore if this condition is detected, and if the required jar
+ * libraries are available, then applets can be executed.
+ */
+
+ /*
+ * executing applets with IE6 embedded can crash, so do not
+ * attempt this if the version is less than IE7
+ */
+ if (!IE.IsIE7) return false;
+
+ if (canExecuteApplets == null) {
+ WebBrowser webBrowser = ((Browser)getParent ().getParent ()).webBrowser;
+ String script = "try {var element = document.createElement('object');element.classid='clsid:CAFEEFAC-DEC7-0000-0000-ABCDEFFEDCBA';return element.object.isPlugin2();} catch (err) {};return false;"; //$NON-NLS-1$
+ canExecuteApplets = ((Boolean)webBrowser.evaluate (script));
+ if (canExecuteApplets.booleanValue ()) {
+ try {
+ Class.forName ("sun.plugin2.main.server.IExplorerPlugin"); /* plugin.jar */ //$NON-NLS-1$
+ Class.forName ("com.sun.deploy.services.Service"); /* deploy.jar */ //$NON-NLS-1$
+ Class.forName ("com.sun.javaws.Globals"); /* javaws.jar */ //$NON-NLS-1$
+ } catch (ClassNotFoundException e) {
+ /* one or more of the required jar libraries are not available */
+ canExecuteApplets = Boolean.FALSE;
+ }
+ }
+ }
+ return canExecuteApplets.booleanValue ();
+}
+
+int QueryCustomPolicy(int /*long*/ pwszUrl, int /*long*/ guidKey, int /*long*/ ppPolicy, int /*long*/ pcbPolicy, int /*long*/ pContext, int cbContext, int dwReserved) {
+ return IE.INET_E_DEFAULT_ACTION;
+}
+
+int SetZoneMapping(int dwZone, int /*long*/ lpszPattern, int dwFlags) {
+ return IE.INET_E_DEFAULT_ACTION;
+}
+
+int GetZoneMappings(int dwZone, int /*long*/ ppenumString, int dwFlags) {
+ return COM.E_NOTIMPL;
+}
+
+/* IOleCommandTarget */
+int QueryStatus(int /*long*/ pguidCmdGroup, int cCmds, int /*long*/ prgCmds, int /*long*/ pCmdText) {
+ return COM.E_NOTSUPPORTED;
+}
+
+int Exec(int /*long*/ pguidCmdGroup, int nCmdID, int nCmdExecOpt, int /*long*/ pvaIn, int /*long*/ pvaOut) {
+ if (pguidCmdGroup != 0) {
+ GUID guid = new GUID();
+ COM.MoveMemory(guid, pguidCmdGroup, GUID.sizeof);
+
+ /*
+ * If a javascript error occurred then suppress IE's default script error dialog.
+ */
+ if (COM.IsEqualGUID(guid, COM.CGID_DocHostCommandHandler)) {
+ if (nCmdID == OLECMDID_SHOWSCRIPTERROR) return COM.S_OK;
+ }
+
+ /*
+ * Bug in Internet Explorer. OnToolBar TRUE is also fired when any of the
+ * address bar or menu bar are requested but not the tool bar. A workaround
+ * has been posted by a Microsoft developer on the public webbrowser_ctl
+ * newsgroup. The workaround is to implement the IOleCommandTarget interface
+ * to test the argument of an undocumented command.
+ */
+ if (nCmdID == 1 && COM.IsEqualGUID(guid, COM.CGID_Explorer) && ((nCmdExecOpt & 0xFFFF) == 0xA)) {
+ IE browser = (IE)((Browser)getParent().getParent()).webBrowser;
+ browser.toolBar = (nCmdExecOpt & 0xFFFF0000) != 0;
+ }
+ }
+ return COM.E_NOTSUPPORTED;
+}
+
+/* IAuthenticate */
+
+int Authenticate (int /*long*/ hwnd, int /*long*/ szUsername, int /*long*/ szPassword) {
+ IE browser = (IE)((Browser)getParent ().getParent ()).webBrowser;
+ for (int i = 0; i < browser.authenticationListeners.length; i++) {
+ AuthenticationEvent event = new AuthenticationEvent (browser.browser);
+ event.location = browser.lastNavigateURL;
+ browser.authenticationListeners[i].authenticate (event);
+ if (!event.doit) return COM.E_ACCESSDENIED;
+ if (event.user != null && event.password != null) {
+ TCHAR user = new TCHAR (0, event.user, true);
+ int size = user.length () * TCHAR.sizeof;
+ int /*long*/ userPtr = COM.CoTaskMemAlloc (size);
+ OS.MoveMemory (userPtr, user, size);
+ TCHAR password = new TCHAR (0, event.password, true);
+ size = password.length () * TCHAR.sizeof;
+ int /*long*/ passwordPtr = COM.CoTaskMemAlloc (size);
+ OS.MoveMemory (passwordPtr, password, size);
+ C.memmove (hwnd, new int /*long*/[] {0}, C.PTR_SIZEOF);
+ C.memmove (szUsername, new int /*long*/[] {userPtr}, C.PTR_SIZEOF);
+ C.memmove (szPassword, new int /*long*/[] {passwordPtr}, C.PTR_SIZEOF);
+ return COM.S_OK;
+ }
+ }
+
+ /* no listener handled the challenge, so defer to the native dialog */
+ C.memmove (hwnd, new int /*long*/[] {getShell().handle}, C.PTR_SIZEOF);
+ return COM.S_OK;
+}
+
+/* IDispatch */
+
+int GetTypeInfoCount (int /*long*/ pctinfo) {
+ C.memmove (pctinfo, new int[] {0}, 4);
+ return COM.S_OK;
+}
+
+int GetTypeInfo (int iTInfo, int lcid, int /*long*/ ppTInfo) {
+ return COM.S_OK;
+}
+
+int GetIDsOfNames (int riid, int /*long*/ rgszNames, int cNames, int lcid, int /*long*/ rgDispId) {
+ int /*long*/[] ptr = new int /*long*/[1];
+ OS.MoveMemory (ptr, rgszNames, C.PTR_SIZEOF);
+ int length = OS.wcslen (ptr[0]);
+ char[] buffer = new char[length];
+ OS.MoveMemory (buffer, ptr[0], length * 2);
+ String functionName = String.valueOf (buffer);
+ int result = COM.S_OK;
+ int[] ids = new int[cNames]; /* DISPIDs */
+ if (functionName.equals ("callJava")) { //$NON-NLS-1$
+ for (int i = 0; i < cNames; i++) {
+ ids[i] = i + 1;
+ }
+ } else {
+ result = COM.DISP_E_UNKNOWNNAME;
+ for (int i = 0; i < cNames; i++) {
+ ids[i] = COM.DISPID_UNKNOWN;
+ }
+ }
+ OS.MoveMemory (rgDispId, ids, cNames * 4);
+ return result;
+}
+
+int Invoke (int dispIdMember, int /*long*/ riid, int lcid, int dwFlags, int /*long*/ pDispParams, int /*long*/ pVarResult, int /*long*/ pExcepInfo, int /*long*/ pArgErr) {
+ DISPPARAMS dispParams = new DISPPARAMS ();
+ COM.MoveMemory (dispParams, pDispParams, DISPPARAMS.sizeof);
+ if (dispParams.cArgs != 2) {
+ if (pVarResult != 0) {
+ COM.MoveMemory (pVarResult, new int /*long*/[] {0}, C.PTR_SIZEOF);
+ }
+ return COM.S_OK;
+ }
+
+ int /*long*/ ptr = dispParams.rgvarg + Variant.sizeof;
+ Variant variant = Variant.win32_new (ptr);
+ int index = variant.getInt ();
+ variant.dispose ();
+ if (index <= 0) {
+ if (pVarResult != 0) {
+ COM.MoveMemory (pVarResult, new int /*long*/[] {0}, C.PTR_SIZEOF);
+ }
+ return COM.S_OK;
+ }
+
+ variant = Variant.win32_new (dispParams.rgvarg);
+ IE ie = (IE)((Browser)getParent ().getParent ()).webBrowser;
+ Object key = new Integer (index);
+ BrowserFunction function = (BrowserFunction)ie.functions.get (key);
+ Object returnValue = null;
+ if (function != null) {
+ try {
+ Object temp = convertToJava (variant);
+ if (temp instanceof Object[]) {
+ Object[] args = (Object[])temp;
+ try {
+ returnValue = function.function (args);
+ } catch (Exception e) {
+ /* exception during function invocation */
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ /* invalid argument value type */
+ if (function.isEvaluate) {
+ /* notify the function so that a java exception can be thrown */
+ function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
+ }
+ returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
+ }
+ }
+ variant.dispose ();
+
+ if (pVarResult != 0) {
+ if (returnValue == null) {
+ COM.MoveMemory (pVarResult, new int /*long*/[] {0}, C.PTR_SIZEOF);
+ } else {
+ try {
+ variant = convertToJS (returnValue);
+ } catch (SWTException e) {
+ /* invalid return value type */
+ variant = convertToJS (WebBrowser.CreateErrorString (e.getLocalizedMessage ()));
+ }
+ Variant.win32_copy (pVarResult, variant);
+ variant.dispose ();
+ }
+ }
+ return COM.S_OK;
+}
+
+Object convertToJava (Variant variant) {
+ switch (variant.getType ()) {
+ case OLE.VT_NULL: return null;
+ case OLE.VT_BSTR: return variant.getString ();
+ case OLE.VT_BOOL: return new Boolean (variant.getBoolean ());
+ case OLE.VT_I2:
+ case OLE.VT_I4:
+ case OLE.VT_I8:
+ case OLE.VT_R4:
+ case OLE.VT_R8:
+ return new Double (variant.getDouble ());
+ case OLE.VT_DISPATCH: {
+ Object[] args = null;
+ OleAutomation auto = variant.getAutomation ();
+ TYPEATTR typeattr = auto.getTypeInfoAttributes ();
+ if (typeattr != null) {
+ GUID guid = new GUID ();
+ guid.Data1 = typeattr.guid_Data1;
+ guid.Data2 = typeattr.guid_Data2;
+ guid.Data3 = typeattr.guid_Data3;
+ guid.Data4 = typeattr.guid_Data4;
+ if (COM.IsEqualGUID (guid, COM.IIDIJScriptTypeInfo)) {
+ int[] rgdispid = auto.getIDsOfNames (new String[] {"length"}); //$NON-NLS-1$
+ if (rgdispid != null) {
+ Variant varLength = auto.getProperty (rgdispid[0]);
+ int length = varLength.getInt ();
+ varLength.dispose ();
+ args = new Object[length];
+ for (int i = 0; i < length; i++) {
+ rgdispid = auto.getIDsOfNames (new String[] {String.valueOf (i)});
+ if (rgdispid != null) {
+ Variant current = auto.getProperty (rgdispid[0]);
+ try {
+ args[i] = convertToJava (current);
+ current.dispose ();
+ } catch (IllegalArgumentException e) {
+ /* invalid argument value type */
+ current.dispose ();
+ auto.dispose ();
+ throw e;
+ }
+ }
+ }
+ }
+ } else {
+ auto.dispose ();
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ auto.dispose ();
+ return args;
+ }
+ }
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ return null;
+}
+
+Variant convertToJS (Object value) {
+ if (value == null) {
+ return new Variant ();
+ }
+ if (value instanceof String) {
+ return new Variant ((String)value);
+ }
+ if (value instanceof Boolean) {
+ return new Variant (((Boolean)value).booleanValue ());
+ }
+ if (value instanceof Number) {
+ return new Variant (((Number)value).doubleValue ());
+ }
+ if (value instanceof Object[]) {
+ Object[] arrayValue = (Object[])value;
+ int length = arrayValue.length;
+ if (length > 0) {
+ /* get IHTMLDocument2 */
+ IE browser = (IE)((Browser)getParent ().getParent ()).webBrowser;
+ OleAutomation auto = browser.auto;
+ int[] rgdispid = auto.getIDsOfNames (new String[] {"Document"}); //$NON-NLS-1$
+ if (rgdispid == null) return new Variant ();
+ Variant pVarResult = auto.getProperty (rgdispid[0]);
+ if (pVarResult == null) return new Variant ();
+ if (pVarResult.getType () == COM.VT_EMPTY) {
+ pVarResult.dispose ();
+ return new Variant ();
+ }
+ OleAutomation document = pVarResult.getAutomation ();
+ pVarResult.dispose ();
+
+ /* get IHTMLWindow2 */
+ rgdispid = document.getIDsOfNames (new String[] {"parentWindow"}); //$NON-NLS-1$
+ if (rgdispid == null) {
+ document.dispose ();
+ return new Variant ();
+ }
+ pVarResult = document.getProperty (rgdispid[0]);
+ if (pVarResult == null || pVarResult.getType () == COM.VT_EMPTY) {
+ if (pVarResult != null) pVarResult.dispose ();
+ document.dispose ();
+ return new Variant ();
+ }
+ OleAutomation ihtmlWindow2 = pVarResult.getAutomation ();
+ pVarResult.dispose ();
+ document.dispose ();
+
+ /* create a new JS array to be returned */
+ rgdispid = ihtmlWindow2.getIDsOfNames (new String[] {"Array"}); //$NON-NLS-1$
+ if (rgdispid == null) {
+ ihtmlWindow2.dispose ();
+ return new Variant ();
+ }
+ Variant arrayType = ihtmlWindow2.getProperty (rgdispid[0]);
+ ihtmlWindow2.dispose ();
+ IDispatch arrayTypeDispatch = arrayType.getDispatch ();
+ arrayType.dispose ();
+
+ int /*long*/[] result = new int /*long*/[1];
+ int rc = arrayTypeDispatch.QueryInterface (COM.IIDIDispatchEx, result);
+ if (rc != COM.S_OK) return new Variant ();
+ IDispatchEx arrayTypeDispatchEx = new IDispatchEx (result[0]);
+ result[0] = 0;
+ int /*long*/ resultPtr = OS.GlobalAlloc (OS.GMEM_FIXED | OS.GMEM_ZEROINIT, VARIANT.sizeof);
+ DISPPARAMS params = new DISPPARAMS ();
+ rc = arrayTypeDispatchEx.InvokeEx (COM.DISPID_VALUE, COM.LOCALE_USER_DEFAULT, COM.DISPATCH_CONSTRUCT, params, resultPtr, null, 0);
+ if (rc != COM.S_OK) {
+ OS.GlobalFree (resultPtr);
+ return new Variant ();
+ }
+ Variant array = Variant.win32_new (resultPtr);
+ OS.GlobalFree (resultPtr);
+
+ /* populate the array */
+ auto = array.getAutomation ();
+ int[] rgdispids = auto.getIDsOfNames (new String[] {"push"}); //$NON-NLS-1$
+ if (rgdispids != null) {
+ for (int i = 0; i < length; i++) {
+ Object currentObject = arrayValue[i];
+ try {
+ Variant variant = convertToJS (currentObject);
+ auto.invoke (rgdispids[0], new Variant[] {variant});
+ variant.dispose ();
+ } catch (SWTException e) {
+ /* invalid return value type */
+ auto.dispose ();
+ array.dispose ();
+ throw e;
+ }
+ }
+ }
+ auto.dispose ();
+ return array;
+ }
+ }
+ SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
+ return null;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/wpf/org/eclipse/swt/browser/IE.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/wpf/org/eclipse/swt/browser/IE.java
new file mode 100644
index 0000000000..babe61d6af
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/wpf/org/eclipse/swt/browser/IE.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2003, 2008 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 org.eclipse.swt.*;
+import org.eclipse.swt.internal.wpf.*;
+import org.eclipse.swt.widgets.*;
+
+class IE extends WebBrowser {
+
+ int frame;
+
+ boolean ignoreDispose;
+
+ static {
+ NativeClearSessions = new Runnable() {
+ public void run() {
+// OS.InternetSetOption (0, OS.INTERNET_OPTION_END_BROWSER_SESSION, 0, 0);
+ }
+ };
+ }
+
+public void create(Composite parent, int style) {
+ frame = OS.gcnew_Frame();
+ if (frame == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.Frame_NavigationUIVisibility(frame, OS.NavigationUIVisibility_Hidden);
+ int parentHandle = browser.handle;
+ int children = OS.Panel_Children(parentHandle);
+ OS.UIElementCollection_Insert(children, 0, frame);
+ OS.GCHandle_Free(children);
+ OS.FrameworkElement_Width(frame, OS.FrameworkElement_Width(parentHandle));
+ OS.FrameworkElement_Height(frame, OS.FrameworkElement_Height(parentHandle));
+
+ Listener listener = new Listener() {
+ public void handleEvent(Event event) {
+ switch (event.type) {
+ case SWT.Dispose: {
+ if (ignoreDispose) {
+ ignoreDispose = false;
+ break;
+ }
+ ignoreDispose = true;
+ browser.notifyListeners (event.type, event);
+ event.type = SWT.NONE;
+ OS.GCHandle_Free(frame);
+ frame = 0;
+ break;
+ }
+ case SWT.Resize: {
+ OS.FrameworkElement_Width(frame, OS.FrameworkElement_Width(browser.handle));
+ OS.FrameworkElement_Height(frame, OS.FrameworkElement_Height(browser.handle));
+ break;
+ }
+ }
+ }
+ };
+ browser.addListener(SWT.Resize, listener);
+ browser.addListener(SWT.Dispose, listener);
+}
+
+public boolean back() {
+ if (!OS.Frame_CanGoBack(frame)) return false;
+ OS.Frame_GoBack(frame);
+ return true;
+}
+
+public boolean execute(String script) {
+// /* get IHTMLDocument2 */
+// int[] rgdispid = auto.getIDsOfNames(new String[]{"Document"}); //$NON-NLS-1$
+// int dispIdMember = rgdispid[0];
+// Variant pVarResult = auto.getProperty(dispIdMember);
+// if (pVarResult == null || pVarResult.getType() == COM.VT_EMPTY) return false;
+// OleAutomation document = pVarResult.getAutomation();
+// pVarResult.dispose();
+//
+// /* get IHTMLWindow2 */
+// rgdispid = document.getIDsOfNames(new String[]{"parentWindow"}); //$NON-NLS-1$
+// if (rgdispid == null) {
+// /* implies that browser's content is not a IHTMLDocument2 (eg.- acrobat reader) */
+// document.dispose();
+// return false;
+// }
+// dispIdMember = rgdispid[0];
+// pVarResult = document.getProperty(dispIdMember);
+// OleAutomation ihtmlWindow2 = pVarResult.getAutomation();
+// pVarResult.dispose();
+// document.dispose();
+//
+// rgdispid = ihtmlWindow2.getIDsOfNames(new String[] { "execScript", "code" }); //$NON-NLS-1$ //$NON-NLS-2$
+// Variant[] rgvarg = new Variant[1];
+// rgvarg[0] = new Variant(script);
+// int[] rgdispidNamedArgs = new int[1];
+// rgdispidNamedArgs[0] = rgdispid[1];
+// pVarResult = ihtmlWindow2.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+// rgvarg[0].dispose();
+// ihtmlWindow2.dispose();
+// if (pVarResult == null) return false;
+// pVarResult.dispose();
+ return true;
+}
+
+public boolean forward() {
+ if (!OS.Frame_CanGoForward(frame)) return false;
+ OS.Frame_GoForward(frame);
+ return true;
+}
+
+public String getBrowserType () {
+ return "ie"; //$NON-NLS-1$
+}
+
+public String getUrl() {
+ int uri = OS.Frame_Source(frame);
+ int str = OS.Object_ToString(uri);
+ int charArray = OS.String_ToCharArray(str);
+ char[] chars = new char[OS.String_Length(str)];
+ OS.memcpy(chars, charArray, chars.length * 2);
+ OS.GCHandle_Free(charArray);
+ String url = new String(chars);
+ OS.GCHandle_Free(str);
+ OS.GCHandle_Free(uri);
+ return url;
+}
+
+public boolean isBackEnabled() {
+ return OS.Frame_CanGoBack(frame);
+}
+
+public boolean isForwardEnabled() {
+ return OS.Frame_CanGoForward(frame);
+}
+
+public void refresh() {
+ OS.Frame_Refresh(frame);
+}
+
+public boolean setText(String html) {
+ return true;
+// /*
+// * If the html field is non-null then the about:blank page is already being
+// * loaded, so no Stop or Navigate is required. Just set the html that is to
+// * be shown.
+// */
+// boolean blankLoading = this.html != null;
+// this.html = html;
+// if (blankLoading) return true;
+//
+// /*
+// * Navigate to the blank page and insert the given html when
+// * receiving the next DocumentComplete notification. See the
+// * MSDN article "Loading HTML content from a Stream".
+// *
+// * Note. Stop any pending request. This is required to avoid displaying a
+// * blank page as a result of consecutive calls to setUrl and/or setText.
+// * The previous request would otherwise render the new html content and
+// * reset the html field before the browser actually navigates to the blank
+// * page as requested below.
+// *
+// * Feature in Internet Explorer. Stopping pending requests when no request
+// * is pending causes a default page 'Action cancelled' to be displayed. The
+// * workaround is to not invoke 'stop' when no request has been set since
+// * that instance was created.
+// */
+// int[] rgdispid;
+// if (navigate) {
+// /*
+// * Stopping the loading of a page causes DocumentComplete events from previous
+// * requests to be received before the DocumentComplete for this page. In such
+// * cases we must be sure to not set the html into the browser too soon, since
+// * doing so could result in its page being cleared out by a subsequent
+// * DocumentComplete. The Browser's ReadyState can be used to determine whether
+// * these extra events will be received or not.
+// */
+// rgdispid = auto.getIDsOfNames(new String[] { "ReadyState" }); //$NON-NLS-1$
+// Variant pVarResult = auto.getProperty(rgdispid[0]);
+// if (pVarResult == null) return false;
+// delaySetText = pVarResult.getInt() != READYSTATE_COMPLETE;
+// pVarResult.dispose();
+// rgdispid = auto.getIDsOfNames(new String[] { "Stop" }); //$NON-NLS-1$
+// auto.invoke(rgdispid[0]);
+// }
+// rgdispid = auto.getIDsOfNames(new String[] { "Navigate", "URL" }); //$NON-NLS-1$ //$NON-NLS-2$
+// navigate = true;
+// Variant[] rgvarg = new Variant[1];
+// rgvarg[0] = new Variant(ABOUT_BLANK);
+// int[] rgdispidNamedArgs = new int[1];
+// rgdispidNamedArgs[0] = rgdispid[1];
+// Variant pVarResult = auto.invoke(rgdispid[0], rgvarg, rgdispidNamedArgs);
+// rgvarg[0].dispose();
+// if (pVarResult == null) return false;
+// boolean result = pVarResult.getType() == OLE.VT_EMPTY;
+// pVarResult.dispose();
+// return result;
+}
+
+public boolean setUrl(String url) {
+ if (url.indexOf(':') == -1) url = "http://" + url;
+ int length = url.length ();
+ char [] buffer = new char [length + 1];
+ url.getChars (0, length, buffer, 0);
+ int str = OS.gcnew_String (buffer);
+ int uri = OS.gcnew_Uri(str, OS.UriKind_RelativeOrAbsolute);
+ OS.GCHandle_Free(str);
+ boolean result = OS.Frame_Navigate(frame, uri);
+ OS.GCHandle_Free(uri);
+ return result;
+}
+
+public void stop() {
+ OS.Frame_StopLoading (frame);
+}
+}

Back to the top