|
/******************************************************************************* |
|
* Copyright (c) 2000, 2006 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 |
|
*******************************************************************************/ |
|
// Modified by Google |
|
package org.eclipse.swt.browser; |
|
|
|
import org.eclipse.swt.*; |
|
import org.eclipse.swt.graphics.Point; |
|
import org.eclipse.swt.graphics.Rectangle; |
|
import org.eclipse.swt.internal.Callback; |
|
import org.eclipse.swt.internal.carbon.*; |
|
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><p> |
|
* IMPORTANT: This class is <em>not</em> intended to be subclassed. |
|
* </p> |
|
* |
|
* @since 3.0 |
|
*/ |
|
public class Browser extends Composite { |
|
|
|
/* Package Name */ |
|
static final String PACKAGE_PREFIX = "org.eclipse.swt.browser."; //$NON-NLS-1$ |
|
static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$ |
|
// GOOGLE: patched in from https://bugs.eclipse.org/bugs/show_bug.cgi?id=161259 |
|
static final String CLEAR_GRAB_BIT = "org.eclipse.swt.internal.carbon.clearGrabBit"; //$NON-NLS-1$ |
|
static final String BROWSER_WINDOW = "org.eclipse.swt.browser.Browser.Window"; //$NON-NLS-1$ |
|
static final int MAX_PROGRESS = 100; |
|
|
|
/* External Listener management */ |
|
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]; |
|
|
|
static Callback Callback3, Callback7; |
|
|
|
/* Objective-C WebView delegate */ |
|
int delegate; |
|
|
|
/* Carbon HIView handle */ |
|
int webViewHandle; |
|
|
|
boolean changingLocation; |
|
String html; |
|
int identifier; |
|
int resourceCount; |
|
String url = ""; |
|
Point location; |
|
Point size; |
|
boolean statusBar = true, toolBar = true, ignoreDispose; |
|
//TEMPORARY CODE |
|
// boolean doit; |
|
|
|
static final int MIN_SIZE = 16; |
|
|
|
/** |
|
* 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(parent, 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) { |
|
dispose(); |
|
SWT.error(SWT.ERROR_NO_HANDLES); |
|
} |
|
int outControl[] = new int[1]; |
|
try { |
|
WebKit.HIWebViewCreate(outControl); |
|
} catch (UnsatisfiedLinkError e) { |
|
dispose(); |
|
SWT.error(SWT.ERROR_NO_HANDLES); |
|
} |
|
webViewHandle = outControl[0]; |
|
if (webViewHandle == 0) { |
|
dispose(); |
|
SWT.error(SWT.ERROR_NO_HANDLES); |
|
} |
|
Display display = getDisplay(); |
|
display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), this}); |
|
// GOOGLE: patched in from https://bugs.eclipse.org/bugs/show_bug.cgi?id=161259 |
|
setData(CLEAR_GRAB_BIT, null); |
|
|
|
/* |
|
* 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]); |
|
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 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. |
|
*/ |
|
int window = OS.GetControlOwner(handle); |
|
if (OS.HIVIEW) { |
|
int[] contentView = new int[1]; |
|
OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView); |
|
OS.HIViewAddSubview(contentView[0], webViewHandle); |
|
OS.HIViewChangeFeatures(webViewHandle, OS.kHIViewFeatureIsOpaque, 0); |
|
} else { |
|
OS.HIViewAddSubview(handle, webViewHandle); |
|
} |
|
OS.HIViewSetVisible(webViewHandle, true); |
|
if (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(handle)}); |
|
OS.SendEventToEventTarget(showEvent[0], OS.GetWindowEventTarget(window)); |
|
if (showEvent[0] != 0) OS.ReleaseEvent(showEvent[0]); |
|
} |
|
|
|
final int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
/* |
|
* 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 = WebKit.objc_msgSend(WebKit.C_NSNotificationCenter, WebKit.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; |
|
notifyListeners (e.type, e); |
|
e.type = SWT.NONE; |
|
|
|
Shell shell = getShell(); |
|
shell.removeListener(SWT.Resize, this); |
|
shell.removeListener(SWT.Show, this); |
|
shell.removeListener(SWT.Hide, this); |
|
Control c = Browser.this; |
|
do { |
|
c.removeListener(SWT.Show, this); |
|
c.removeListener(SWT.Hide, this); |
|
c = c.getParent(); |
|
} while (c != shell); |
|
|
|
e.display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), null}); |
|
|
|
WebKit.objc_msgSend(webView, WebKit.S_setFrameLoadDelegate, 0); |
|
WebKit.objc_msgSend(webView, WebKit.S_setResourceLoadDelegate, 0); |
|
WebKit.objc_msgSend(webView, WebKit.S_setUIDelegate, 0); |
|
WebKit.objc_msgSend(webView, WebKit.S_setPolicyDelegate, 0); |
|
WebKit.objc_msgSend(notificationCenter, WebKit.S_removeObserver, delegate); |
|
|
|
WebKit.objc_msgSend(delegate, WebKit.S_release); |
|
if (OS.HIVIEW) OS.DisposeControl(webViewHandle); |
|
html = null; |
|
break; |
|
} |
|
case SWT.Hide: { |
|
/* |
|
* 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 Hide and Show events on the browser's parents |
|
* and set its size to 0 in Hide and to restore its size in Show. |
|
*/ |
|
CGRect bounds = new CGRect(); |
|
bounds.x = bounds.y = -MIN_SIZE; |
|
bounds.width = bounds.height = MIN_SIZE; |
|
OS.HIViewSetFrame(webViewHandle, bounds); |
|
break; |
|
} |
|
case SWT.Show: { |
|
/* |
|
* Do not update size when it is not visible. Note that isVisible() |
|
* cannot be used because SWT.Show is sent before the widget is |
|
* actually visible. |
|
*/ |
|
Shell shell = getShell(); |
|
Composite parent = Browser.this; |
|
while (parent != shell && (parent.getVisible() || parent == e.widget)) { |
|
parent = parent.getParent(); |
|
} |
|
if (!(parent.getVisible() || parent == e.widget)) return; |
|
|
|
/* |
|
* 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 Hide and Show events on the browser's parents |
|
* and set its size to 0 in Hide and to restore its size in Show. |
|
*/ |
|
CGRect bounds = new CGRect(); |
|
if (OS.HIVIEW) { |
|
OS.HIViewGetBounds(handle, bounds); |
|
int[] contentView = new int[1]; |
|
OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(handle)), OS.kHIViewWindowContentID(), contentView); |
|
OS.HIViewConvertRect(bounds, handle, contentView[0]); |
|
} else { |
|
OS.HIViewGetFrame(handle, bounds); |
|
} |
|
/* |
|
* 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 SWT.Resize: { |
|
/* Do not update size when it is not visible */ |
|
if (!isVisible()) return; |
|
/* |
|
* 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. |
|
*/ |
|
CGRect bounds = new CGRect(); |
|
if (OS.HIVIEW) { |
|
OS.HIViewGetBounds(handle, bounds); |
|
int[] contentView = new int[1]; |
|
OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(handle)), OS.kHIViewWindowContentID(), contentView); |
|
OS.HIViewConvertRect(bounds, handle, contentView[0]); |
|
} else { |
|
OS.HIViewGetFrame(handle, bounds); |
|
} |
|
/* |
|
* 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; |
|
if (e.widget == getShell()) { |
|
bounds.x++; |
|
/* Note that the bounds needs to change */ |
|
OS.HIViewSetFrame(webViewHandle, bounds); |
|
bounds.x--; |
|
} |
|
OS.HIViewSetFrame(webViewHandle, bounds); |
|
break; |
|
} |
|
} |
|
} |
|
}; |
|
addListener(SWT.Dispose, listener); |
|
addListener(SWT.Resize, listener); |
|
Shell shell = getShell(); |
|
shell.addListener(SWT.Resize, listener); |
|
shell.addListener(SWT.Show, listener); |
|
shell.addListener(SWT.Hide, listener); |
|
Control c = this; |
|
do { |
|
c.addListener(SWT.Show, listener); |
|
c.addListener(SWT.Hide, listener); |
|
c = c.getParent(); |
|
} while (c != shell); |
|
|
|
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.kEventClassTextInput, OS.kEventTextInputUnicodeForKeyEvent, |
|
}; |
|
int controlTarget = OS.GetControlEventTarget(webViewHandle); |
|
OS.InstallEventHandler(controlTarget, callback3Address, mask.length / 2, mask, webViewHandle, null); |
|
|
|
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 = WebKit.objc_msgSend(WebKit.C_WebKitDelegate, WebKit.S_alloc); |
|
delegate = WebKit.objc_msgSend(delegate, WebKit.S_initWithProc, callback7Address, webViewHandle); |
|
|
|
// [webView setFrameLoadDelegate:delegate]; |
|
WebKit.objc_msgSend(webView, WebKit.S_setFrameLoadDelegate, delegate); |
|
|
|
// [webView setResourceLoadDelegate:delegate]; |
|
WebKit.objc_msgSend(webView, WebKit.S_setResourceLoadDelegate, delegate); |
|
|
|
// [webView setUIDelegate:delegate]; |
|
WebKit.objc_msgSend(webView, WebKit.S_setUIDelegate, delegate); |
|
|
|
/* register delegate for all notifications sent out from webview */ |
|
WebKit.objc_msgSend(notificationCenter, WebKit.S_addObserver_selector_name_object, delegate, WebKit.S_handleNotification, 0, webView); |
|
|
|
// [webView setPolicyDelegate:delegate]; |
|
WebKit.objc_msgSend(webView, WebKit.S_setPolicyDelegate, delegate); |
|
|
|
// [webView setDownloadDelegate:delegate]; |
|
WebKit.objc_msgSend(webView, WebKit.S_setDownloadDelegate, delegate); |
|
} |
|
|
|
/** |
|
* Clears all session cookies from all current Browser instances. |
|
* |
|
* @since 3.2 |
|
*/ |
|
public static void clearSessions () { |
|
int storage = WebKit.objc_msgSend (WebKit.C_NSHTTPCookieStorage, WebKit.S_sharedHTTPCookieStorage); |
|
int cookies = WebKit.objc_msgSend (storage, WebKit.S_cookies); |
|
int count = WebKit.objc_msgSend (cookies, WebKit.S_count); |
|
for (int i = 0; i < count; i++) { |
|
int cookie = WebKit.objc_msgSend (cookies, WebKit.S_objectAtIndex, i); |
|
boolean isSession = WebKit.objc_msgSend (cookie, WebKit.S_isSessionOnly) != 0; |
|
if (isSession) { |
|
WebKit.objc_msgSend (storage, WebKit.S_deleteCookie, cookie); |
|
} |
|
} |
|
} |
|
|
|
static int eventProc3(int nextHandler, int theEvent, int userData) { |
|
Widget widget = Display.getCurrent().findWidget(userData); |
|
if (widget instanceof Browser) |
|
return ((Browser)widget).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 ((Browser)widget).handleCallback(selector, arg0, arg1, arg2, arg3); |
|
return 0; |
|
} |
|
|
|
/** |
|
* 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); |
|
CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length + 1]; |
|
System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, closeWindowListeners.length); |
|
closeWindowListeners = newCloseWindowListeners; |
|
closeWindowListeners[closeWindowListeners.length - 1] = 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); |
|
LocationListener[] newLocationListeners = new LocationListener[locationListeners.length + 1]; |
|
System.arraycopy(locationListeners, 0, newLocationListeners, 0, locationListeners.length); |
|
locationListeners = newLocationListeners; |
|
locationListeners[locationListeners.length - 1] = 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); |
|
OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length + 1]; |
|
System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, openWindowListeners.length); |
|
openWindowListeners = newOpenWindowListeners; |
|
openWindowListeners[openWindowListeners.length - 1] = 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); |
|
ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length + 1]; |
|
System.arraycopy(progressListeners, 0, newProgressListeners, 0, progressListeners.length); |
|
progressListeners = newProgressListeners; |
|
progressListeners[progressListeners.length - 1] = 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); |
|
StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length + 1]; |
|
System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, statusTextListeners.length); |
|
statusTextListeners = newStatusTextListeners; |
|
statusTextListeners[statusTextListeners.length - 1] = 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); |
|
TitleListener[] newTitleListeners = new TitleListener[titleListeners.length + 1]; |
|
System.arraycopy(titleListeners, 0, newTitleListeners, 0, titleListeners.length); |
|
titleListeners = newTitleListeners; |
|
titleListeners[titleListeners.length - 1] = 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); |
|
VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length + 1]; |
|
System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, visibilityWindowListeners.length); |
|
visibilityWindowListeners = newVisibilityWindowListeners; |
|
visibilityWindowListeners[visibilityWindowListeners.length - 1] = 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(); |
|
html = null; |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
return WebKit.objc_msgSend(webView, WebKit.S_goBack) != 0; |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
/** |
|
* Execute the specified script. |
|
* |
|
* <p> |
|
* Execute a script containing javascript commands in the context of the current document. |
|
* |
|
* @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> |
|
* |
|
* @since 3.1 |
|
*/ |
|
public boolean execute(String script) { |
|
checkWidget(); |
|
if (script == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); |
|
|
|
int length = script.length(); |
|
char[] buffer = new char[length]; |
|
script.getChars(0, length, buffer, 0); |
|
int string = OS.CFStringCreateWithCharacters(0, buffer, length); |
|
|
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
int value = WebKit.objc_msgSend(webView, WebKit.S_stringByEvaluatingJavaScriptFromString, string); |
|
OS.CFRelease(string); |
|
return value != 0; |
|
} |
|
|
|
/** |
|
* 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(); |
|
html = null; |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
return WebKit.objc_msgSend(webView, WebKit.S_goForward) != 0; |
|
} |
|
|
|
/** |
|
* 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 url; |
|
} |
|
|
|
int handleCallback(int nextHandler, int theEvent) { |
|
int eventKind = OS.GetEventKind(theEvent); |
|
switch (eventKind) { |
|
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 (!isVisible ()) return OS.noErr; |
|
|
|
/* |
|
* GOOGLE: HACK - SWT does not properly push repaint events back to |
|
* WebKit, so we actually naively tell webkit to repaint it's entire |
|
* client area. |
|
*/ |
|
setNeedsDisplay(true); |
|
|
|
break; |
|
} |
|
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; |
|
break; |
|
} |
|
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; |
|
// GOOGLE |
|
case 99: fireWindowScriptObjectListeners(arg0); break; |
|
} |
|
return ret; |
|
} |
|
|
|
/** |
|
* 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(); |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
return WebKit.objc_msgSend(webView, WebKit.S_canGoBack) != 0; |
|
} |
|
|
|
/** |
|
* 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(); |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
return WebKit.objc_msgSend(webView, WebKit.S_canGoForward) != 0; |
|
} |
|
|
|
/** |
|
* 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(); |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
WebKit.objc_msgSend(webView, WebKit.S_reload, 0); |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* 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); |
|
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; |
|
} |
|
|
|
/** |
|
* Renders HTML. |
|
* |
|
* <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); |
|
/* |
|
* Bug in Safari. The web view segment faults in some circunstances |
|
* 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); |
|
|
|
String baseURL = "about:blank"; //$NON-NLS-1$ |
|
length = baseURL.length(); |
|
buffer = new char[length]; |
|
baseURL.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 = WebKit.objc_msgSend(WebKit.C_NSURL, WebKit.S_URLWithString, URLString); |
|
OS.CFRelease(URLString); |
|
|
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
|
|
//mainFrame = [webView mainFrame]; |
|
int mainFrame = WebKit.objc_msgSend(webView, WebKit.S_mainFrame); |
|
|
|
//[mainFrame loadHTMLString:(NSString *) string baseURL:(NSURL *)URL]; |
|
WebKit.objc_msgSend(mainFrame, WebKit.S_loadHTMLStringbaseURL, string, URL); |
|
OS.CFRelease(string); |
|
} |
|
|
|
/** |
|
* Loads a URL. |
|
* |
|
* @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); |
|
|
|
html = null; |
|
|
|
StringBuffer buffer = new StringBuffer(); |
|
if (url.indexOf('/') == 0) buffer.append("file://"); //$NON-NLS-1$ //$NON-NLS-2$ |
|
else if (url.indexOf(':') == -1) buffer.append("http://"); //$NON-NLS-1$ |
|
for (int i = 0; i < url.length(); i++) { |
|
char c = url.charAt(i); |
|
if (c == ' ') buffer.append("%20"); //$NON-NLS-1$ //$NON-NLS-2$ |
|
else buffer.append(c); |
|
} |
|
|
|
int length = buffer.length(); |
|
char[] chars = new char[length]; |
|
buffer.getChars(0, length, chars, 0); |
|
int sHandle = OS.CFStringCreateWithCharacters(0, chars, length); |
|
|
|
/* |
|
* Note. URLWithString uses autorelease. The resulting URL |
|
* does not need to be released. |
|
* inURL = [NSURL URLWithString:(NSString *)sHandle] |
|
*/ |
|
int inURL= WebKit.objc_msgSend(WebKit.C_NSURL, WebKit.S_URLWithString, sHandle); |
|
OS.CFRelease(sHandle); |
|
|
|
//request = [NSURLRequest requestWithURL:(NSURL*)inURL]; |
|
int request= WebKit.objc_msgSend(WebKit.C_NSURLRequest, WebKit.S_requestWithURL, inURL); |
|
|
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
|
|
//mainFrame = [webView mainFrame]; |
|
int mainFrame= WebKit.objc_msgSend(webView, WebKit.S_mainFrame); |
|
|
|
//[mainFrame loadRequest:request]; |
|
WebKit.objc_msgSend(mainFrame, WebKit.S_loadRequest, request); |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* 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(); |
|
html = null; |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
WebKit.objc_msgSend(webView, WebKit.S_stopLoading, 0); |
|
} |
|
|
|
/* WebFrameLoadDelegate */ |
|
|
|
void didFailProvisionalLoadWithError(int error, int frame) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
if (frame == WebKit.objc_msgSend(webView, WebKit.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. 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 didFinishLoadForFrame(int frame) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) { |
|
final Display display= getDisplay(); |
|
final ProgressEvent progress = new ProgressEvent(this); |
|
progress.display = getDisplay(); |
|
progress.widget = this; |
|
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 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() && !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. 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 didReceiveTitle(int title, int frame) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
if (frame == WebKit.objc_msgSend(webView, WebKit.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.this); |
|
newEvent.display = getDisplay(); |
|
newEvent.widget = this; |
|
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) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
//id url= [[[[frame provisionalDataSource] request] URL] absoluteString]; |
|
int dataSource = WebKit.objc_msgSend(frame, WebKit.S_dataSource); |
|
int request = WebKit.objc_msgSend(dataSource, WebKit.S_request); |
|
int url = WebKit.objc_msgSend(request, WebKit.S_URL); |
|
int s = WebKit.objc_msgSend(url, WebKit.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); |
|
final Display display = getDisplay(); |
|
|
|
boolean top = frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame); |
|
if (top) { |
|
/* reset resource status variables */ |
|
resourceCount = 0; |
|
this.url = url2; |
|
|
|
final ProgressEvent progress = new ProgressEvent(this); |
|
progress.display = display; |
|
progress.widget = this; |
|
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() && !isDisposed()) |
|
listener.changed(progress); |
|
} |
|
} |
|
); |
|
} |
|
|
|
StatusTextEvent statusText = new StatusTextEvent(this); |
|
statusText.display = display; |
|
statusText.widget = this; |
|
statusText.text = url2; |
|
for (int i = 0; i < statusTextListeners.length; i++) |
|
statusTextListeners[i].changed(statusText); |
|
} |
|
LocationEvent location = new LocationEvent(Browser.this); |
|
location.display = display; |
|
location.widget = this; |
|
location.location = url2; |
|
location.top = top; |
|
for (int i = 0; i < locationListeners.length; i++) |
|
locationListeners[i].changed(location); |
|
} |
|
|
|
/* 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; |
|
} |
|
|
|
int identifierForInitialRequest(int request, int dataSource) { |
|
final Display display = getDisplay(); |
|
final ProgressEvent progress = new ProgressEvent(this); |
|
progress.display = display; |
|
progress.widget = this; |
|
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() && !isDisposed()) |
|
listener.changed(progress); |
|
} |
|
} |
|
); |
|
} |
|
|
|
/* |
|
* Note. numberWithInt uses autorelease. The resulting object |
|
* does not need to be released. |
|
* identifier = [NSNumber numberWithInt: resourceCount++] |
|
*/ |
|
int identifier = WebKit.objc_msgSend(WebKit.C_NSNumber, WebKit.S_numberWithInt, resourceCount++); |
|
|
|
if (this.identifier == 0) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
int frame = WebKit.objc_msgSend(dataSource, WebKit.S_webFrame); |
|
if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) this.identifier = identifier; |
|
} |
|
return identifier; |
|
|
|
} |
|
|
|
int willSendRequest(int identifier, int request, int redirectResponse, int dataSource) { |
|
return request; |
|
} |
|
|
|
/* handleNotification */ |
|
|
|
void handleNotification(int notification) { |
|
} |
|
|
|
/* UIDelegate */ |
|
int createWebViewWithRequest(int request) { |
|
WindowEvent newEvent = new WindowEvent(Browser.this); |
|
newEvent.display = getDisplay(); |
|
newEvent.widget = this; |
|
newEvent.required = true; |
|
if (openWindowListeners != null) { |
|
for (int i = 0; i < openWindowListeners.length; i++) |
|
openWindowListeners[i].open(newEvent); |
|
} |
|
int webView = 0; |
|
Browser browser = newEvent.browser; |
|
if (browser != null && !browser.isDisposed()) { |
|
webView = WebKit.HIWebViewGetWebView(browser.webViewHandle); |
|
|
|
if (request != 0) { |
|
//mainFrame = [webView mainFrame]; |
|
int mainFrame= WebKit.objc_msgSend(webView, WebKit.S_mainFrame); |
|
|
|
//[mainFrame loadRequest:request]; |
|
WebKit.objc_msgSend(mainFrame, WebKit.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 = getShell(); |
|
Point pt = parent.getSize(); |
|
parent.setSize(pt.x+1, pt.y); |
|
parent.setSize(pt.x, pt.y); |
|
WindowEvent newEvent = new WindowEvent(this); |
|
newEvent.display = getDisplay(); |
|
newEvent.widget = this; |
|
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 in Safari. 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.memcpy(dest, frame, 16); |
|
/* convert to SWT system coordinates */ |
|
Rectangle bounds = 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(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(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(getShell(), SWT.NONE); |
|
String result = dialog.open(); |
|
if (result == null) { |
|
WebKit.objc_msgSend(resultListener, WebKit.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); |
|
WebKit.objc_msgSend(resultListener, WebKit.S_chooseFilename, filename); |
|
OS.CFRelease(filename); |
|
} |
|
void webViewClose() { |
|
Shell parent = getShell(); |
|
WindowEvent newEvent = new WindowEvent(this); |
|
newEvent.display = getDisplay(); |
|
newEvent.widget = this; |
|
for (int i = 0; i < closeWindowListeners.length; i++) |
|
closeWindowListeners[i].close(newEvent); |
|
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; |
|
notifyListeners(SWT.MenuDetect, event); |
|
Menu menu = getMenu(); |
|
if (!event.doit) return 0; |
|
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(this); |
|
statusText.display = getDisplay(); |
|
statusText.widget = this; |
|
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; |
|
} |
|
|
|
/* PolicyDelegate */ |
|
|
|
void decidePolicyForMIMEType(int type, int request, int frame, int listener) { |
|
boolean canShow = WebKit.objc_msgSend(WebKit.C_WebView, WebKit.S_canShowMIMEType, type) != 0; |
|
WebKit.objc_msgSend(listener, canShow ? WebKit.S_use : WebKit.S_download); |
|
} |
|
|
|
void decidePolicyForNavigationAction(int actionInformation, int request, int frame, int listener) { |
|
int url = WebKit.objc_msgSend(request, WebKit.S_URL); |
|
if (url == 0) { |
|
/* indicates that a URL with an invalid format was specified */ |
|
WebKit.objc_msgSend(listener, WebKit.S_ignore); |
|
return; |
|
} |
|
int s = WebKit.objc_msgSend(url, WebKit.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); |
|
|
|
LocationEvent newEvent = new LocationEvent(this); |
|
newEvent.display = getDisplay(); |
|
newEvent.widget = this; |
|
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; |
|
} |
|
|
|
WebKit.objc_msgSend(listener, newEvent.doit ? WebKit.S_use : WebKit.S_ignore); |
|
|
|
if (html != null && !isDisposed()) { |
|
String html = this.html; |
|
this.html = null; |
|
_setText(html); |
|
} |
|
} |
|
|
|
void decidePolicyForNewWindowAction(int actionInformation, int request, int frameName, int listener) { |
|
WebKit.objc_msgSend(listener, WebKit.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); |
|
FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); |
|
dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$ |
|
dialog.setFileName(name); |
|
String path = dialog.open(); |
|
if (path == null) { |
|
/* cancel pressed */ |
|
WebKit.objc_msgSend(download, WebKit.S_release); |
|
return; |
|
} |
|
length = path.length(); |
|
char[] chars = new char[length]; |
|
path.getChars(0, length, chars, 0); |
|
int result = OS.CFStringCreateWithCharacters(0, chars, length); |
|
WebKit.objc_msgSend(download, WebKit.S_setDestinationAllowOverwrite, result, 1); |
|
OS.CFRelease(result); |
|
} |
|
|
|
// GOOGLE: we need a notification when the window object is available so we can |
|
// setup our own hooks before any JavaScript runs. |
|
public interface WindowScriptObjectListener { |
|
public void windowScriptObjectAvailable(int windowScriptObject); |
|
} |
|
|
|
public void addWindowScriptObjectListener(WindowScriptObjectListener listener) { |
|
checkWidget(); |
|
if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); |
|
WindowScriptObjectListener[] newWindowScriptObjectListeners = new WindowScriptObjectListener[windowScriptObjectListeners.length + 1]; |
|
System.arraycopy(windowScriptObjectListeners, 0, newWindowScriptObjectListeners, 0, windowScriptObjectListeners.length); |
|
windowScriptObjectListeners = newWindowScriptObjectListeners; |
|
windowScriptObjectListeners[windowScriptObjectListeners.length - 1] = listener; |
|
} |
|
|
|
public void removeWindowScriptObjectListener(WindowScriptObjectListener listener) { |
|
checkWidget(); |
|
if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); |
|
if (windowScriptObjectListeners.length == 0) return; |
|
int index = -1; |
|
for (int i = 0; i < windowScriptObjectListeners.length; i++) { |
|
if (listener == windowScriptObjectListeners[i]) { |
|
index = i; |
|
break; |
|
} |
|
} |
|
if (index == -1) return; |
|
if (windowScriptObjectListeners.length == 1) { |
|
windowScriptObjectListeners = new WindowScriptObjectListener[0]; |
|
return; |
|
} |
|
WindowScriptObjectListener[] newWindowScriptObjectListeners = new WindowScriptObjectListener[windowScriptObjectListeners.length - 1]; |
|
System.arraycopy(windowScriptObjectListeners, 0, newWindowScriptObjectListeners, 0, index); |
|
System.arraycopy(windowScriptObjectListeners, index + 1, newWindowScriptObjectListeners, index, windowScriptObjectListeners.length - index - 1); |
|
windowScriptObjectListeners = newWindowScriptObjectListeners; |
|
} |
|
|
|
void fireWindowScriptObjectListeners(int windowScriptObject) { |
|
for (int i = 0; i < windowScriptObjectListeners.length; i++) { |
|
windowScriptObjectListeners[i].windowScriptObjectAvailable(windowScriptObject); |
|
} |
|
} |
|
|
|
public static void setWebInspectorEnabled(boolean isEnabled) { |
|
char[] name = "WebKitDeveloperExtras".toCharArray(); |
|
int clsId = WebKit.objc_getClass("NSUserDefaults"); |
|
if (clsId == 0) return; |
|
int sel_sud = WebKit.sel_registerName("standardUserDefaults"); |
|
if (sel_sud == 0) return; |
|
int objId = WebKit.objc_msgSend(clsId, sel_sud); |
|
if (objId == 0) return; |
|
int sel_sbfk = WebKit.sel_registerName("setBool:forKey:"); |
|
if (sel_sbfk == 0) return; |
|
int cfName = OS.CFStringCreateWithCharacters(0,name,name.length); |
|
if (cfName == 0) return; |
|
try { |
|
WebKit.objc_msgSend(objId, sel_sbfk, isEnabled ? 1 : 0, cfName); |
|
} finally { |
|
OS.CFRelease(cfName); |
|
} |
|
} |
|
|
|
public void setUserAgentApplicationName(String userAgent) { |
|
char[] chars = userAgent.toCharArray(); |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
if (webView == 0) return; |
|
int sel = WebKit.sel_registerName("setApplicationNameForUserAgent:"); |
|
if (sel == 0) return; |
|
int userAgentStr = OS.CFStringCreateWithCharacters(0, chars, chars.length); |
|
if (userAgentStr == 0) return; |
|
try { |
|
WebKit.objc_msgSend(webView, sel, userAgentStr); |
|
} finally { |
|
OS.CFRelease(userAgentStr); |
|
} |
|
} |
|
|
|
public void setNeedsDisplay(boolean value) { |
|
int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
|
if (webView == 0) return; |
|
int sel = WebKit.sel_registerName("setNeedsDisplay:"); |
|
if (sel == 0) return; |
|
WebKit.objc_msgSend(webView, sel, (value)?1:0); |
|
} |
|
|
|
WindowScriptObjectListener[] windowScriptObjectListeners = new WindowScriptObjectListener[0]; |
|
// end GOOGLE |
|
} |