diff dwt/browser/Safari.d @ 45:d8635bb48c7c

Merge with SWT 3.5
author Jacob Carlborg <doob@me.com>
date Mon, 01 Dec 2008 17:07:00 +0100
parents 7d135fe0caf2
children cfa563df4fdd
line wrap: on
line diff
--- a/dwt/browser/Safari.d	Tue Oct 21 15:20:04 2008 +0200
+++ b/dwt/browser/Safari.d	Mon Dec 01 17:07:00 2008 +0100
@@ -1,5 +1,5 @@
-/*******************************************************************************
- * Copyright (c) 2000, 2007 IBM Corporation and others.
+/*******************************************************************************
+ * Copyright (c) 2000, 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
@@ -7,37 +7,31 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     
- * Port to the D programming language:
- *     Jacob Carlborg <jacob.carlborg@gmail.com>
  *******************************************************************************/
 module dwt.browser.Safari;
 
+import dwt.dwthelper.utils;
+
 import dwt.DWT;
-import dwt.browser.LocationEvent;
-import dwt.browser.ProgressEvent;
-import dwt.browser.ProgressListener;
-import dwt.browser.StatusTextEvent;
-import dwt.browser.TitleEvent;
-import dwt.browser.TitleListener;
-import dwt.browser.WebBrowser;
-import dwt.dwthelper.utils;
 import dwt.graphics.Point;
 import dwt.graphics.Rectangle;
+import dwt.internal.C;
 import dwt.internal.Callback;
+import dwt.internal.Compatibility;
 import dwt.internal.cocoa.DOMDocument;
-import dwt.internal.cocoa.DOMEvent;
 import dwt.internal.cocoa.DOMKeyboardEvent;
 import dwt.internal.cocoa.DOMMouseEvent;
 import dwt.internal.cocoa.DOMWheelEvent;
 import dwt.internal.cocoa.NSArray;
 import dwt.internal.cocoa.NSDictionary;
+import dwt.internal.cocoa.NSError;
 import dwt.internal.cocoa.NSHTTPCookie;
 import dwt.internal.cocoa.NSHTTPCookieStorage;
 import dwt.internal.cocoa.NSNotificationCenter;
 import dwt.internal.cocoa.NSNumber;
 import dwt.internal.cocoa.NSPrintInfo;
 import dwt.internal.cocoa.NSPrintOperation;
+import dwt.internal.cocoa.NSRect;
 import dwt.internal.cocoa.NSString;
 import dwt.internal.cocoa.NSURL;
 import dwt.internal.cocoa.NSURLDownload;
@@ -53,7 +47,6 @@
 import dwt.internal.cocoa.WebPreferences;
 import dwt.internal.cocoa.WebView;
 import dwt.internal.cocoa.id;
-
 import dwt.widgets.Composite;
 import dwt.widgets.Display;
 import dwt.widgets.Event;
@@ -62,65 +55,57 @@
 import dwt.widgets.Menu;
 import dwt.widgets.MessageBox;
 import dwt.widgets.Shell;
-
-import Math = tango.math.Math;
-
-import dwt.dwthelper.Runnable;
+import dwt.widgets.Widget;
 
-class Safari : WebBrowser
-{
+class Safari extends WebBrowser {
     WebView webView;
-    DWTWebViewDelegate delegatee;
-    int jniRef;
+    SWTWebViewDelegate delegate;
     bool changingLocation;
     String lastHoveredLinkURL;
     String html;
-    int identifier;
+    int /*long*/ identifier;
     int resourceCount;
-    String url = "";
+    String url = ""; //$NON-NLS-1$
     Point location;
     Point size;
     bool statusBar = true, toolBar = true, ignoreDispose;
     int lastMouseMoveX, lastMouseMoveY;
     //TEMPORARY CODE
-    //  bool doit;
+//  bool doit;
 
     static bool Initialized;
-    static Callback Callback2, Callback3, Callback4, Callback5, Callback6, Callback7;
-
-    static const int MIN_SIZE = 16;
-    static const int MAX_PROGRESS = 100;
-    static const String WebElementLinkURLKey = "WebElementLinkURL"; //$NON-NLS-1$
-    static const String AGENT_STRING = "Safari/unknown"; //$NON-NLS-1$
-    static const String URI_FROMMEMORY = "file:///"; //$NON-NLS-1$
-    static const String PROTOCOL_FILE = "file:"; //$NON-NLS-1$
-    static const String PROTOCOL_HTTP = "http:"; //$NON-NLS-1$
-    static const String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
-    static const String SAFARI_EVENTS_FIX_KEY = "dwt.internal.safariEventsFix"; //$NON-NLS-1$
+    // the following Callbacks are never freed
+    static Callback Callback3, Callback4, Callback5, Callback6, Callback7;
 
-    /* event Strings */
-    static const String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
-    static const String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
-    static const String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
-    static const String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
-    static const String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
-    static const String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
+    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 ADD_WIDGET_KEY = "dwt.internal.addWidget"; //$NON-NLS-1$
+    static final String SAFARI_EVENTS_FIX_KEY = "dwt.internal.safariEventsFix"; //$NON-NLS-1$
+    static final String DWT_OBJECT = "DWT_OBJECT"; //$NON-NLS-1$
 
-    static this ()
-    {
-        NativeClearSessions = new class Runnable
-        {
-            public void run ()
-            {
+    /* 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 = cookies.count();
-                
-                for (int i = 0; i < count; i++)
-                {
+                int /*long*/ count = cookies.count();
+                for (int i = 0; i < count; i++) {
                     NSHTTPCookie cookie = new NSHTTPCookie(cookies.objectAtIndex(i));
-                    if (cookie.isSessionOnly())
-                    {
+                    if (cookie.isSessionOnly()) {
                         storage.deleteCookie(cookie);
                     }
                 }
@@ -128,1439 +113,1134 @@
         };
     }
 
-    public void create (Composite parent, int style)
-    {
-
-        String className = "DWTWebViewDelegate";
-        if (OS.objc_lookUpClass(className) == 0)
-        {
-            ClassInfo safaryClass = this.classinfo;
-            Callback2 = new Callback(safaryClass, "browserProc", 2);
-            int proc2 = Callback2.getAddress();
-            if (proc2 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-            Callback3 = new Callback(safaryClass, "browserProc", 3);
-            int proc3 = Callback3.getAddress();
-            if (proc3 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-            Callback4 = new Callback(safaryClass, "browserProc", 4);
-            int proc4 = Callback4.getAddress();
-            if (proc4 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-            Callback5 = new Callback(safaryClass, "browserProc", 5);
-            int proc5 = Callback5.getAddress();
-            if (proc5 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-            Callback6 = new Callback(safaryClass, "browserProc", 6);
-            int proc6 = Callback6.getAddress();
-            if (proc6 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-            Callback7 = new Callback(safaryClass, "browserProc", 7);
-            int proc7 = Callback7.getAddress();
-            if (proc7 is 0)
-                DWT.error(DWT.ERROR_NO_MORE_CALLBACKS);
-
-            int cls = OS.objc_allocateClassPair(OS.class_WebView, className, 0);
-            OS.class_addIvar(cls, "tag", OS.PTR_SIZEOF, cast(byte) (Math.log(OS.PTR_SIZEOF) / Math.log(2)), "i");
-            OS.class_addMethod(cls, OS.sel_tag, proc2, "@:");
-            OS.class_addMethod(cls, OS.sel_setTag_1, proc3, "@:i");
-            OS.class_addMethod(cls, OS.sel_webView_1didChangeLocationWithinPageForFrame_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1didFailProvisionalLoadWithError_1forFrame_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1didFinishLoadForFrame_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1didReceiveTitle_1forFrame_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1didStartProvisionalLoadForFrame_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1didCommitLoadForFrame_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1resource_1didFinishLoadingFromDataSource_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1resource_1didFailLoadingWithError_1fromDataSource_1, proc6, "@:@@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1identifierForInitialRequest_1fromDataSource_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1resource_1willSendRequest_1redirectResponse_1fromDataSource_1, proc7, "@:@@@@@");
-            OS.class_addMethod(cls, OS.sel_handleNotification_1, proc3, "@:@");
-            OS.class_addMethod(cls, OS.sel_webView_1createWebViewWithRequest_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webViewShow_1, proc3, "@:@");
-            OS.class_addMethod(cls, OS.sel_webView_1setFrame_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webViewClose_1, proc3, "@:@");
-            OS.class_addMethod(cls, OS.sel_webView_1contextMenuItemsForElement_1defaultMenuItems_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1setStatusBarVisible_1, proc4, "@:@B");
-            OS.class_addMethod(cls, OS.sel_webView_1setResizable_1, proc4, "@:@B");
-            OS.class_addMethod(cls, OS.sel_webView_1setToolbarsVisible_1, proc4, "@:@B");
-            OS.class_addMethod(cls, OS.sel_webView_1setStatusText_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webViewFocus_1, proc3, "@:@");
-            OS.class_addMethod(cls, OS.sel_webViewUnfocus_1, proc3, "@:@");
-            OS.class_addMethod(cls, OS.sel_webView_1runJavaScriptAlertPanelWithMessage_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1runJavaScriptConfirmPanelWithMessage_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1runOpenPanelForFileButtonWithResultListener_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1mouseDidMoveOverElement_1modifierFlags_1, proc5, "@:@@I");
-            OS.class_addMethod(cls, OS.sel_webView_1printFrameView_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_webView_1decidePolicyForMIMEType_1request_1frame_1decisionListener_1, proc7, "@:@@@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1decidePolicyForNavigationAction_1request_1frame_1decisionListener_1, proc7, "@:@@@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1decidePolicyForNewWindowAction_1request_1newFrameName_1decisionListener_1, proc7, "@:@@@@@");
-            OS.class_addMethod(cls, OS.sel_webView_1unableToImplementPolicyWithError_1frame_1, proc5, "@:@@@");
-            OS.class_addMethod(cls, OS.sel_download_1decideDestinationWithSuggestedFilename_1, proc4, "@:@@");
-            OS.class_addMethod(cls, OS.sel_handleEvent_1, proc3, "@:@");
-            OS.objc_registerClassPair(cls);
-        }
-
-        /*
-         * 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 = cast(WebView) (new WebView()).alloc();
-        if (webView is null)
-            DWT.error(DWT.ERROR_NO_HANDLES);
-        webView.initWithFrame(browser.view.frame(), null, null);
-        webView.setAutoresizingMask(OS.NSViewWidthSizable | OS.NSViewHeightSizable);
-        jniRef = OS.NewGlobalRef(this);
-        if (jniRef is 0)
-            DWT.error(DWT.ERROR_NO_HANDLES);
-        const DWTWebViewDelegate delegatee = cast(DWTWebViewDelegate) (new DWTWebViewDelegate()).alloc().init();
-        delegatee.setTag(jniRef);
-        this.delegatee = delegatee;
-        this.webView = webView;
-        browser.view.addSubview_(webView);
-
-        const NSNotificationCenter notificationCenter = NSNotificationCenter.defaultCenter();
+public void create (Composite parent, int style) {
+    String className = "SWTWebViewDelegate"; //$NON-NLS-1$
+    if (OS.objc_lookUpClass(className) is 0) {
+        Class safariClass = this.getClass();
+        Callback3 = new Callback(safariClass, "browserProc", 3); //$NON-NLS-1$
+        int /*long*/ proc3 = Callback3.getAddress();
+        if (proc3 is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
+        Callback4 = new Callback(safariClass, "browserProc", 4); //$NON-NLS-1$
+        int /*long*/ proc4 = Callback4.getAddress();
+        if (proc4 is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
+        Callback5 = new Callback(safariClass, "browserProc", 5); //$NON-NLS-1$
+        int /*long*/ proc5 = Callback5.getAddress();
+        if (proc5 is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
+        Callback6 = new Callback(safariClass, "browserProc", 6); //$NON-NLS-1$
+        int /*long*/ proc6 = Callback6.getAddress();
+        if (proc6 is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
+        Callback7 = new Callback(safariClass, "browserProc", 7); //$NON-NLS-1$
+        int /*long*/ proc7 = Callback7.getAddress();
+        if (proc7 is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
+        int /*long*/ setFrameProc = OS.webView_setFrame_CALLBACK(proc4);
+        if (setFrameProc is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS);
 
-        Listener listener = new class (notificationCenter) Listener
-        {
-            NSNotificationCenter notificationCenter;
-            
-            this (NSNotificationCenter notificationCenter)
-            {
-                this.notificationCenter = notificationCenter;
-            }
-            
-            public void handleEvent (Event e)
-            {
-                switch (e.type)
-                {
-                    case DWT.Dispose:
-                    {
-                        /* make this handler run after other dispose listeners */
-                        if (ignoreDispose)
-                        {
-                            ignoreDispose = false;
-                            break;
-                        }
-                        ignoreDispose = true;
-                        browser.notifyListeners(e.type, e);
-                        e.type = DWT.NONE;
-
-                        webView.setFrameLoadDelegate(null);
-                        webView.setResourceLoadDelegate(null);
-                        webView.setUIDelegate(null);
-                        webView.setPolicyDelegate(null);
-                        webView.setDownloadDelegate(null);
-                        notificationCenter.removeObserver(delegatee);
-
-                        webView.release();
-                        webView = null;
-                        delegatee.release();
-                        delegatee = null;
-                        OS.DeleteGlobalRef(jniRef);
-                        jniRef = 0;
-                        html = null;
-                        lastHoveredLinkURL = null;
-                        break;
-                    }
-                }
-            }
-        };
-        browser.addListener(DWT.Dispose, listener);
-
-        webView.setFrameLoadDelegate(delegatee);
-        webView.setResourceLoadDelegate(delegatee);
-        webView.setUIDelegate(delegatee);
-        notificationCenter.addObserver(delegatee, OS.sel_handleNotification_1, null, webView);
-        webView.setPolicyDelegate(delegatee);
-        webView.setDownloadDelegate(delegatee);
-        webView.setApplicationNameForUserAgent(NSString.StringWith(AGENT_STRING));
-
-        if (!Initialized)
-        {
-            Initialized = true;
-            /* disable applets */
-            WebPreferences.standardPreferences().setJavaEnabled(false);
-        }
-    }
-
-    public bool back ()
-    {
-        html = null;
-        return webView.goBack();
-    }
-
-    static int browserProc (int delegatee, int sel)
-    {
-        if (sel is OS.sel_tag)
-        {
-            int[] tag = new int[1];
-            OS.object_getInstanceVariable(delegatee, "tag", tag);
-            return tag[0];
-        }
-        return 0;
-    }
-
-    static int browserProc (int id, int sel, int arg0)
-    {
-        if (sel is OS.sel_setTag_1)
-        {
-            OS.object_setInstanceVariable(id, "tag", arg0);
-            return 0;
-        }
-        int jniRef = OS.objc_msgSend(id, OS.sel_tag);
-        if (jniRef is 0 || jniRef is -1)
-            return 0;
-        Safari widget = cast(Safari) OS.JNIGetObject(jniRef);
-        if (widget is null)
-            return 0;
-        if (sel is OS.sel_handleNotification_1)
-        {
-            widget.handleNotification(arg0);
-        }
-        else if (sel is OS.sel_webViewShow_1)
-        {
-            widget.webViewShow(arg0);
-        }
-        else if (sel is OS.sel_webViewClose_1)
-        {
-            widget.webViewClose(arg0);
-        }
-        else if (sel is OS.sel_webViewFocus_1)
-        {
-            widget.webViewFocus(arg0);
-        }
-        else if (sel is OS.sel_webViewUnfocus_1)
-        {
-            widget.webViewUnfocus(arg0);
-        }
-        else if (sel is OS.sel_handleEvent_1)
-        {
-            widget.handleEvent(arg0);
-        }
-        return 0;
-    }
+        String types = "*"; //$NON-NLS-1$
+        int size = C.PTR_SIZEOF, align = C.PTR_SIZEOF is 4 ? 2 : 3;
 
-    static int browserProc (int id, int sel, int arg0, int arg1)
-    {
-        if (sel is OS.sel_setTag_1)
-        {
-            OS.object_setInstanceVariable(id, "tag", arg0);
-            return 0;
-        }
-        int jniRef = OS.objc_msgSend(id, OS.sel_tag);
-        if (jniRef is 0 || jniRef is -1)
-            return 0;
-        Safari widget = cast(Safari) OS.JNIGetObject(jniRef);
-        if (widget is null)
-            return 0;
-        if (sel is OS.sel_webView_1didChangeLocationWithinPageForFrame_1)
-        {
-            widget.webView_didChangeLocationWithinPageForFrame(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1didFinishLoadForFrame_1)
-        {
-            widget.webView_didFinishLoadForFrame(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1didStartProvisionalLoadForFrame_1)
-        {
-            widget.webView_didStartProvisionalLoadForFrame(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1didCommitLoadForFrame_1)
-        {
-            widget.webView_didCommitLoadForFrame(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1setFrame_1)
-        {
-            widget.webView_setFrame(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1createWebViewWithRequest_1)
-        {
-            return widget.webView_createWebViewWithRequest(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1setStatusBarVisible_1)
-        {
-            widget.webView_setStatusBarVisible(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1setResizable_1)
-        {
-            widget.webView_setResizable(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1setStatusText_1)
-        {
-            widget.webView_setStatusText(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1setToolbarsVisible_1)
-        {
-            widget.webView_setToolbarsVisible(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1runJavaScriptAlertPanelWithMessage_1)
-        {
-            widget.webView_runJavaScriptAlertPanelWithMessage(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1runJavaScriptConfirmPanelWithMessage_1)
-        {
-            return widget.webView_runJavaScriptConfirmPanelWithMessage(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1runOpenPanelForFileButtonWithResultListener_1)
-        {
-            widget.webView_runOpenPanelForFileButtonWithResultListener(arg0, arg1);
-        }
-        else if (sel is OS.sel_download_1decideDestinationWithSuggestedFilename_1)
-        {
-            widget.download_decideDestinationWithSuggestedFilename(arg0, arg1);
-        }
-        else if (sel is OS.sel_webView_1printFrameView_1)
-        {
-            widget.webView_printFrameView(arg0, arg1);
-        }
-        return 0;
-    }
-
-    static int browserProc (int id, int sel, int arg0, int arg1, int arg2)
-    {
-        int jniRef = OS.objc_msgSend(id, OS.sel_tag);
-        if (jniRef is 0 || jniRef is -1)
-            return 0;
-        Safari widget = cast(Safari) OS.JNIGetObject(jniRef);
-        if (widget is null)
-            return 0;
-        if (sel is OS.sel_webView_1didFailProvisionalLoadWithError_1forFrame_1)
-        {
-            widget.webView_didFailProvisionalLoadWithError_forFrame(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1didReceiveTitle_1forFrame_1)
-        {
-            widget.webView_didReceiveTitle_forFrame(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1resource_1didFinishLoadingFromDataSource_1)
-        {
-            widget.webView_resource_didFinishLoadingFromDataSource(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1identifierForInitialRequest_1fromDataSource_1)
-        {
-            return widget.webView_identifierForInitialRequest_fromDataSource(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1contextMenuItemsForElement_1defaultMenuItems_1)
-        {
-            return widget.webView_contextMenuItemsForElement_defaultMenuItems(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1mouseDidMoveOverElement_1modifierFlags_1)
-        {
-            widget.webView_mouseDidMoveOverElement_modifierFlags(arg0, arg1, arg2);
-        }
-        else if (sel is OS.sel_webView_1unableToImplementPolicyWithError_1frame_1)
-        {
-            widget.webView_unableToImplementPolicyWithError_frame(arg0, arg1, arg2);
-        }
-        return 0;
-    }
-
-    static int browserProc (int id, int sel, int arg0, int arg1, int arg2, int arg3)
-    {
-        int jniRef = OS.objc_msgSend(id, OS.sel_tag);
-        if (jniRef is 0 || jniRef is -1)
-            return 0;
-        Safari widget = cast(Safari) OS.JNIGetObject(jniRef);
-        if (widget is null)
-            return 0;
-        if (sel is OS.sel_webView_1resource_1didFailLoadingWithError_1fromDataSource_1)
-        {
-            widget.webView_resource_didFailLoadingWithError_fromDataSource(arg0, arg1, arg2, arg3);
-        }
-        return 0;
-    }
-
-    static int browserProc (int id, int sel, int arg0, int arg1, int arg2, int arg3, int arg4)
-    {
-        int jniRef = OS.objc_msgSend(id, OS.sel_tag);
-        if (jniRef is 0 || jniRef is -1)
-            return 0;
-        Safari widget = cast(Safari) OS.JNIGetObject(jniRef);
-        if (widget is null)
-            return 0;
-        if (sel is OS.sel_webView_1resource_1willSendRequest_1redirectResponse_1fromDataSource_1)
-        {
-            return widget.webView_resource_willSendRequest_redirectResponse_fromDataSource(arg0, arg1, arg2, arg3, arg4);
-        }
-        else if (sel is OS.sel_webView_1decidePolicyForMIMEType_1request_1frame_1decisionListener_1)
-        {
-            widget.webView_decidePolicyForMIMEType_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
-        }
-        else if (sel is OS.sel_webView_1decidePolicyForNavigationAction_1request_1frame_1decisionListener_1)
-        {
-            widget.webView_decidePolicyForNavigationAction_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
-        }
-        else if (sel is OS.sel_webView_1decidePolicyForNewWindowAction_1request_1newFrameName_1decisionListener_1)
-        {
-            widget.webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(arg0, arg1, arg2, arg3, arg4);
-        }
-        return 0;
-    }
-
-    public bool execute (String script)
-    {
-        return webView.StringByEvaluatingJavaScriptFromString(NSString.StringWith(script)) !is null;
-    }
-
-    public bool forward ()
-    {
-        html = null;
-        return webView.goForward();
-    }
-
-    public String getText ()
-    {
-        WebFrame mainFrame = webView.mainFrame();
-        WebDataSource dataSource = mainFrame.dataSource();
-        if (dataSource is null)
-            return ""; //$NON-NLS-1$
-        WebDocumentRepresentation representation = dataSource.representation();
-        if (representation is null)
-            return ""; //$NON-NLS-1$
-        NSString source = representation.documentSource();
-        if (source is null)
-            return ""; //$NON-NLS-1$
-        char[] buffer = new char[source.length()];
-        source.getCharacters_(buffer);
-        return new String(buffer);
-    }
-
-    public String getUrl ()
-    {
-        return url;
-    }
-
-    public bool isBackEnabled ()
-    {
-        return webView.canGoBack();
-    }
-
-    public bool isForwardEnabled ()
-    {
-        return webView.canGoForward();
-    }
-
-    public void refresh ()
-    {
-        webView.reload(null);
-    }
-
-    public bool 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.static_URLWithString_(URLString);
-        WebFrame mainFrame = webView.mainFrame();
-        mainFrame.loadHTMLString(String, URL);
-    }
-
-    public bool setUrl (String url)
-    {
-        html = null;
-
-        NSURL inURL;
-        if (url.startsWith(PROTOCOL_FILE))
-        {
-            url = url.substring(PROTOCOL_FILE.length());
-        }
-        bool isHttpURL = url.indexOf('/') !is 0;
-        if (isHttpURL)
-        {
-            if (url.indexOf(':') is -1)
-            {
-                url = PROTOCOL_HTTP + "//" + url; //$NON-NLS-1$
-            }
-            inURL = NSURL.static_URLWithString_(NSString.StringWith(url.toString()));
-        }
-        else
-        {
-            inURL = NSURL.static_fileURLWithPath_(NSString.StringWith(url.toString()));
-        }
-        if (inURL is null)
-            return false;
-
-        NSURLRequest request = NSURLRequest.static_requestWithURL_(inURL);
-        WebFrame mainFrame = webView.mainFrame();
-        mainFrame.loadRequest(request);
-        return true;
-    }
-
-    public void stop ()
-    {
-        html = null;
-        webView.stopLoading(null);
-    }
-
-    /* WebFrameLoadDelegate */
-
-    void webView_didChangeLocationWithinPageForFrame (int sender, int frameID)
-    {
-        WebFrame frame = new WebFrame(frameID);
-        WebDataSource dataSource = frame.dataSource();
-        NSURLRequest request = dataSource.request();
-        NSURL url = request.URL();
-        NSString s = url.absoluteString();
-        int length = s.length();
-        if (length is 0)
-            return;
-        char[] buffer = new char[length];
-        s.getCharacters_(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.opEquals(URI_FROMMEMORY))
-            url2 = ABOUT_BLANK;
-
-        const Display display = browser.getDisplay();
-        bool top = frameID is 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 sender, int error, int frame)
-    {
-        if (frame is 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;
-        }
+        int /*long*/ cls = OS.objc_allocateClassPair(OS.class_NSObject, className, 0);
+        OS.class_addIvar(cls, DWT_OBJECT, size, (byte)align, types);
+        OS.class_addMethod(cls, OS.sel_webView_didChangeLocationWithinPageForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_didFailProvisionalLoadWithError_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_didFinishLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_didReceiveTitle_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_didStartProvisionalLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_didCommitLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_resource_didFinishLoadingFromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_, proc6, "@:@@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_identifierForInitialRequest_fromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_, proc7, "@:@@@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_handleNotification_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_createWebViewWithRequest_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webViewShow_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webViewClose_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_setStatusBarVisible_, proc4, "@:@B"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_setResizable_, proc4, "@:@B"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_setToolbarsVisible_, proc4, "@:@B"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_setStatusText_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webViewFocus_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webViewUnfocus_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_runJavaScriptAlertPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_runJavaScriptConfirmPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_runOpenPanelForFileButtonWithResultListener_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_mouseDidMoveOverElement_modifierFlags_, proc5, "@:@@I"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_printFrameView_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_unableToImplementPolicyWithError_frame_, proc5, "@:@@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_download_decideDestinationWithSuggestedFilename_, proc4, "@:@@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_handleEvent_, proc3, "@:@"); //$NON-NLS-1$
+        OS.class_addMethod(cls, OS.sel_webView_setFrame_, setFrameProc, "@:@{NSRect}"); //$NON-NLS-1$
+        OS.objc_registerClassPair(cls);
     }
 
-    void webView_didFinishLoadForFrame (int sender, int frameID)
-    {
-        hookDOMMouseListeners(frameID);
-        if (frameID is webView.mainFrame().id)
-        {
-            hookDOMKeyListeners(frameID);
+    /*
+    * 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 is null) DWT.error(DWT.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);
+
+    final NSNotificationCenter notificationCenter = NSNotificationCenter.defaultCenter();
 
-            const 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 !is null)
-            {
-                NSString title = dataSource.pageTitle();
-                if (title is null)
-                {   /* page has no title */
-                    const TitleEvent newEvent = new TitleEvent(browser);
-                    newEvent.display = display;
-                    newEvent.widget = browser;
-                    newEvent.title = url;
-                    for (int i = 0; i < titleListeners.length; i++)
-                    {
-                        const TitleListener listener = titleListeners[i];
-                        /*
-                         * Note on WebKit.  Running the event loop from a Browser
-                         * delegatee 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 class (display, listener) Runnable
-                        {
-                            Display display;
-                            TitleListener listener;
-                            
-                            this (Display display, TitleListener listener)
-                            {
-                                this.display = display;
-                                this.listener = listener;
-                            }
-                            
-                            public void run ()
-                            {
-                                if (!display.isDisposed() && !browser.isDisposed())
-                                {
-                                    listener.changed(newEvent);
-                                }
-                            }
-                        });
+    Listener listener = new Listener() {
+        public void handleEvent(Event e) {
+            switch (e.type) {
+                case DWT.FocusIn:
+                    Safari.this.webView.window().makeFirstResponder(Safari.this.webView);
+                    break;
+                case DWT.Dispose: {
+                    /* make this handler run after other dispose listeners */
+                    if (ignoreDispose) {
+                        ignoreDispose = false;
+                        break;
                     }
+                    ignoreDispose = true;
+                    browser.notifyListeners (e.type, e);
+                    e.type = DWT.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);
+                    notificationCenter.removeObserver(delegate);
+
+                    Safari.this.webView.release();
+                    Safari.this.webView = null;
+                    Safari.this.delegate.release();
+                    Safari.this.delegate = null;
+                    html = null;
+                    lastHoveredLinkURL = null;
+                    break;
                 }
             }
-            const 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++)
-            {
-                const ProgressListener listener = progressListeners[i];
-                /*
-                 * Note on WebKit.  Running the event loop from a Browser
-                 * delegatee 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 class (display, listener) Runnable
-                {
-                    Display display;
-                    ProgressListener listener;
-                    
-                    this (Display display, ProgressListener listener)
-                    {
-                        this.display = display;
-                        this.listener = listener;
-                    }
-                    
-                    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 frameID)
-    {
-        WebFrame frame = new WebFrame(frameID);
-        DOMDocument document = frame.DOMDocument();
-
-        NSString type = NSString.StringWith(DOMEVENT_KEYDOWN);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
+    };
+    browser.addListener(DWT.Dispose, listener);
+    /* Needed to be able to tab into the browser */
+    browser.addListener(DWT.KeyDown, listener);
+    browser.addListener(DWT.FocusIn, listener);
 
-        type = NSString.StringWith(DOMEVENT_KEYUP);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
-    }
+    webView.setFrameLoadDelegate(delegate);
+    webView.setResourceLoadDelegate(delegate);
+    webView.setUIDelegate(delegate);    
+    notificationCenter.addObserver(delegate, OS.sel_handleNotification_, null, webView);
+    webView.setPolicyDelegate(delegate);
+    webView.setDownloadDelegate(delegate);
+    webView.setApplicationNameForUserAgent(NSString.stringWith(AGENT_STRING));
 
-    void hookDOMMouseListeners (int frameID)
-    {
-        WebFrame frame = new WebFrame(frameID);
-        DOMDocument document = frame.DOMDocument();
+    if (!Initialized) {
+        Initialized = true;
+        /* disable applets */
+        WebPreferences.standardPreferences().setJavaEnabled(false);
+    }
+}
 
-        NSString type = NSString.StringWith(DOMEVENT_MOUSEDOWN);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
-
-        type = NSString.StringWith(DOMEVENT_MOUSEUP);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
+public bool back() {
+    html = null;    
+    return webView.goBack();
+}
 
-        type = NSString.StringWith(DOMEVENT_MOUSEMOVE);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
-
-        type = NSString.StringWith(DOMEVENT_MOUSEWHEEL);
-        document.addEventListener_listener_useCapture(type, delegatee, false);
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0) {
+    Widget widget = Display.getCurrent().findWidget(id);
+    if (widget is null) return 0;
+    Safari safari = (Safari)((Browser)widget).webBrowser;
+    if (sel is OS.sel_handleNotification_) {
+        safari.handleNotification(arg0);
+    } else if (sel is OS.sel_webViewShow_) {
+        safari.webViewShow(arg0);
+    } else if (sel is OS.sel_webViewClose_) {
+        safari.webViewClose(arg0);
+    } else if (sel is OS.sel_webViewFocus_) {
+        safari.webViewFocus(arg0);
+    } else if (sel is OS.sel_webViewUnfocus_) {
+        safari.webViewUnfocus(arg0);
+    } else if (sel is OS.sel_handleEvent_) {
+        safari.handleEvent(arg0);
     }
+    return 0;
+}
 
-    void webView_didReceiveTitle_forFrame (int sender, int titleID, int frameID)
-    {
-        if (frameID is webView.mainFrame().id)
-        {
-            NSString title = new NSString(titleID);
-            char[] buffer = new char[title.length()];
-            title.getCharacters_(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);
-            }
-        }
+static int /*long*/ browserProc(int /*long*/ id, int /*long*/ sel, int /*long*/ arg0, int /*long*/ arg1) {
+    Widget widget = Display.getCurrent().findWidget(id);
+    if (widget is null) return 0;
+    Safari safari = (Safari)((Browser)widget).webBrowser;
+    if (sel is OS.sel_webView_didChangeLocationWithinPageForFrame_) {
+        safari.webView_didChangeLocationWithinPageForFrame(arg0, arg1);
+    } else if (sel is OS.sel_webView_didFinishLoadForFrame_) {
+        safari.webView_didFinishLoadForFrame(arg0, arg1);
+    } else if (sel is OS.sel_webView_didStartProvisionalLoadForFrame_) {
+        safari.webView_didStartProvisionalLoadForFrame(arg0, arg1);
+    } else if (sel is OS.sel_webView_didCommitLoadForFrame_) {
+        safari.webView_didCommitLoadForFrame(arg0, arg1);
+    } else if (sel is OS.sel_webView_setFrame_) {
+        safari.webView_setFrame(arg0, arg1);
+    } else if (sel is OS.sel_webView_createWebViewWithRequest_) {
+        return safari.webView_createWebViewWithRequest(arg0, arg1);     
+    } else if (sel is OS.sel_webView_setStatusBarVisible_) {
+        safari.webView_setStatusBarVisible(arg0, arg1 !is 0);
+    } else if (sel is OS.sel_webView_setResizable_) {
+        safari.webView_setResizable(arg0, arg1 !is 0);
+    } else if (sel is OS.sel_webView_setStatusText_) {
+        safari.webView_setStatusText(arg0, arg1);
+    } else if (sel is OS.sel_webView_setToolbarsVisible_) {
+        safari.webView_setToolbarsVisible(arg0, arg1 !is 0);
+    } else if (sel is OS.sel_webView_runJavaScriptAlertPanelWithMessage_) {
+        safari.webView_runJavaScriptAlertPanelWithMessage(arg0, arg1);
+    } else if (sel is OS.sel_webView_runJavaScriptConfirmPanelWithMessage_) {
+        return safari.webView_runJavaScriptConfirmPanelWithMessage(arg0, arg1);
+    } else if (sel is OS.sel_webView_runOpenPanelForFileButtonWithResultListener_) {
+        safari.webView_runOpenPanelForFileButtonWithResultListener(arg0, arg1);
+    } else if (sel is OS.sel_download_decideDestinationWithSuggestedFilename_) {
+        safari.download_decideDestinationWithSuggestedFilename(arg0, arg1);
+    } else if (sel is OS.sel_webView_printFrameView_) {
+        safari.webView_printFrameView(arg0, arg1);
     }
+    return 0;
+}
 
-    void webView_didStartProvisionalLoadForFrame (int sender, int 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 is webView.mainFrame().id) {
-    //      /* reset resource status variables */
-    //      resourceCount= 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 is null) return 0;
+    Safari safari = (Safari)((Browser)widget).webBrowser;
+    if (sel is OS.sel_webView_didFailProvisionalLoadWithError_forFrame_) {
+        safari.webView_didFailProvisionalLoadWithError_forFrame(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_didReceiveTitle_forFrame_) {
+        safari.webView_didReceiveTitle_forFrame(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_resource_didFinishLoadingFromDataSource_) {
+        safari.webView_resource_didFinishLoadingFromDataSource(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_identifierForInitialRequest_fromDataSource_) {
+        return safari.webView_identifierForInitialRequest_fromDataSource(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_) {
+        return safari.webView_contextMenuItemsForElement_defaultMenuItems(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_mouseDidMoveOverElement_modifierFlags_) {
+        safari.webView_mouseDidMoveOverElement_modifierFlags(arg0, arg1, arg2);
+    } else if (sel is OS.sel_webView_unableToImplementPolicyWithError_frame_) {
+        safari.webView_unableToImplementPolicyWithError_frame(arg0, arg1, arg2);
     }
+    return 0;
+}
 
-    void webView_didCommitLoadForFrame (int sender, int frameID)
-    {
-        WebFrame frame = new WebFrame(frameID);
-        WebDataSource dataSource = frame.dataSource();
-        NSURLRequest request = dataSource.request();
-        NSURL url = request.URL();
-        NSString s = url.absoluteString();
-        int length = s.length();
-        if (length is 0)
-            return;
-        char[] buffer = new char[length];
-        s.getCharacters_(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.opEquals(URI_FROMMEMORY))
-            url2 = ABOUT_BLANK;
+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 is null) return 0;
+    Safari safari = (Safari)((Browser)widget).webBrowser;
+    if (sel is OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_) {
+        safari.webView_resource_didFailLoadingWithError_fromDataSource(arg0, arg1, arg2, arg3);
+    }   
+    return 0;
+}
 
-        const Display display = browser.getDisplay();
-        bool top = frameID is webView.mainFrame().id;
-        if (top)
-        {
-            /* reset resource status variables */
-            resourceCount = 0;
-            this.url = url2;
+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 is null) return 0;
+    Safari safari = (Safari)((Browser)widget).webBrowser;
+    if (sel is OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_) {
+        return safari.webView_resource_willSendRequest_redirectResponse_fromDataSource(arg0, arg1, arg2, arg3, arg4);
+    } else if (sel is OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_) {
+        safari.webView_decidePolicyForMIMEType_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
+    } else if (sel is OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_) {
+        safari.webView_decidePolicyForNavigationAction_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
+    } else if (sel is OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_) {
+        safari.webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(arg0, arg1, arg2, arg3, arg4);
+    }
+    return 0;
+}
+
+public bool execute(String script) {
+    return webView.stringByEvaluatingJavaScriptFromString(NSString.stringWith(script)) !is null;
+}
+
+public bool forward() {
+    html = null;
+    return webView.goForward();
+}
 
-            const 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++)
-            {
-                const ProgressListener listener = progressListeners[i];
-                /*
-                 * Note on WebKit.  Running the event loop from a Browser
-                 * delegatee 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 class (display, listener) Runnable
-                {
-                    Display display;
-                    ProgressListener listener;
-                    
-                    this (Display display, ProgressListener listener)
-                    {
-                        this.display = display;
-                        this.listener = listener;
-                    }
-                    
-                    public void run ()
-                    {
-                        if (!display.isDisposed() && !browser.isDisposed())
-                            listener.changed(progress);
-                    }
-                });
-            }
+public String getBrowserType () {
+    return "safari"; //$NON-NLS-1$
+}
+
+public String getText() {
+    WebFrame mainFrame = webView.mainFrame();
+    WebDataSource dataSource = mainFrame.dataSource();
+    if (dataSource is null) return "";  //$NON-NLS-1$
+    WebDocumentRepresentation representation = dataSource.representation();
+    if (representation is null) return "";  //$NON-NLS-1$
+    NSString source = representation.documentSource();
+    if (source is null) return "";  //$NON-NLS-1$
+    return source.getString();
+}
+
+public String getUrl() {
+    return url;
+}
+
+public bool isBackEnabled() {
+    return webView.canGoBack();
+}
+
+public bool isForwardEnabled() {
+    return webView.canGoForward();
+}
 
-            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);
-        }
-    }
+public void refresh() {
+    webView.reload(null);
+}
 
-    /* WebResourceLoadDelegate */
-
-    void webView_resource_didFinishLoadingFromDataSource (int sender, int identifier, int dataSource)
-    {
+public bool setText(String html) {
     /*
-     * 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 is identifier) this.identifier = 0;
+    * 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 bool setUrl(String url) {
+    html = null;
+
+    if (url.indexOf('/') is 0) {
+        url = PROTOCOL_FILE + url;
+    } else if (url.indexOf(':') is -1) {
+        url = PROTOCOL_HTTP + url;
     }
 
-    void webView_resource_didFailLoadingWithError_fromDataSource (int sender, 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.  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 is identifier) this.identifier = 0;
-    }
+    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;
+}
 
-    int webView_identifierForInitialRequest_fromDataSource (int sender, int request, int dataSourceID)
-    {
-        const Display display = browser.getDisplay();
-        const 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++)
-        {
-            const ProgressListener listener = progressListeners[i];
-            /*
-             * Note on WebKit.  Running the event loop from a Browser
-             * delegatee 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 class (display, listener) Runnable
-            {
-                Display display;
-                ProgressListener listener;
-                
-                this (Display display, ProgressListener listener)
-                {
-                    this.display = display;
-                    this.listener = listener;
-                }
-                
-                public void run ()
-                {
-                    if (!display.isDisposed() && !browser.isDisposed())
-                        listener.changed(progress);
-                }
-            });
-        }
+public void stop() {
+    html = null;
+    webView.stopLoading(null);
+}
 
-        NSNumber identifier = NSNumber.numberWithInt(resourceCount++);
-        if (this.identifier is 0)
-        {
-            WebDataSource dataSource = new WebDataSource(dataSourceID);
-            WebFrame frame = dataSource.webFrame();
-            if (frame.id is webView.mainFrame().id)
-                this.identifier = identifier.id;
-        }
-        return identifier.id;
-
-    }
-
-    int webView_resource_willSendRequest_redirectResponse_fromDataSource (int sender, int identifier, int request, int redirectResponse,
-            int dataSource)
-    {
-        return request;
-    }
-
-    /* handleNotification */
-
-    void handleNotification (int notification)
-    {
-    }
-
-    /* UIDelegate */
-    int webView_createWebViewWithRequest (int sender, int request)
-    {
-        WindowEvent newEvent = new WindowEvent(browser);
-        newEvent.display = browser.getDisplay();
-        newEvent.widget = browser;
-        newEvent.required = true;
-        if (openWindowListeners !is null)
-        {
-            for (int i = 0; i < openWindowListeners.length; i++)
-            {
-                openWindowListeners[i].open(newEvent);
-            }
-        }
-        Browser browser = null;
-        if (newEvent.browser !is null && cast(Safari) newEvent.browser.webBrowser)
-        {
-            browser = newEvent.browser;
-        }
-        if (browser !is null && !browser.isDisposed())
-        {
-            if (request !is 0)
-            {
-                WebFrame mainFrame = webView.mainFrame();
-                mainFrame.loadRequest(new NSURLRequest(request));
-            }
-        }
-        return webView.id;
-    }
+/* WebFrameLoadDelegate */
 
-    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 !is null)
-            newEvent.location = location;
-        if (size !is 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 webView_setFrame (int sender, int frame)
-    {
-        float[] dest = new float[4];
-        OS.memmove(dest, frame, 16);
-        /* convert to DWT system coordinates */
-        Rectangle bounds = browser.getDisplay().getBounds();
-        location = new Point(cast(int) dest[0], bounds.height - cast(int) dest[1] - cast(int) dest[3]);
-        size = new Point(cast(int) dest[2], cast(int) dest[3]);
-    }
-
-    void webViewFocus (int sender)
-    {
-    }
-
-    void webViewUnfocus (int sender)
-    {
-    }
-
-    void webView_runJavaScriptAlertPanelWithMessage (int sender, int messageID)
-    {
-        NSString message = new NSString(messageID);
-        char[] buffer = new char[message.length()];
-        message.getCharacters_(buffer);
-        String text = new String(buffer);
-
-        MessageBox messageBox = new MessageBox(browser.getShell(), DWT.OK | DWT.ICON_WARNING);
-        messageBox.setText("Javascript"); //$NON-NLS-1$
-        messageBox.setMessage(text);
-        messageBox.open();
-    }
-
-    int webView_runJavaScriptConfirmPanelWithMessage (int sender, int messageID)
-    {
-        NSString message = new NSString(messageID);
-        char[] buffer = new char[message.length()];
-        message.getCharacters_(buffer);
-        String text = new String(buffer);
+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 is 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;
 
-        MessageBox messageBox = new MessageBox(browser.getShell(), DWT.OK | DWT.CANCEL | DWT.ICON_QUESTION);
-        messageBox.setText("Javascript"); //$NON-NLS-1$
-        messageBox.setMessage(text);
-        return messageBox.open() is DWT.OK ? 1 : 0;
-    }
-
-    void webView_runOpenPanelForFileButtonWithResultListener (int sender, int resultListenerID)
-    {
-        FileDialog dialog = new FileDialog(browser.getShell(), DWT.NONE);
-        String result = dialog.open();
-        WebOpenPanelResultListener resultListener = new WebOpenPanelResultListener(resultListenerID);
-        if (result is null)
-        {
-            resultListener.cancel();
-            return;
-        }
-        resultListener.chooseFilename(NSString.StringWith(result));
-    }
-
-    void webViewClose (int 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 webView_contextMenuItemsForElement_defaultMenuItems (int sender, int element, int defaultMenuItems)
-    {
-        Point pt = browser.getDisplay().getCursorLocation();
-        Event event = new Event();
-        event.x = pt.x;
-        event.y = pt.y;
-        browser.notifyListeners(DWT.MenuDetect, event);
-        Menu menu = browser.getMenu();
-        if (!event.doit)
-            return 0;
-        if (menu !is null && !menu.isDisposed())
-        {
-            if (event.x !is pt.x || event.y !is pt.y)
-            {
-                menu.setLocation(event.x, event.y);
-            }
-            menu.setVisible(true);
-            return 0;
-        }
-        return defaultMenuItems;
-    }
-
-    void webView_setStatusBarVisible (int sender, int visible)
-    {
-        /* Note.  Webkit only emits the notification when the status bar should be hidden. */
-        statusBar = visible !is 0;
-    }
-
-    void webView_setStatusText (int sender, int textID)
-    {
-        NSString text = new NSString(textID);
-        int length = text.length();
-        if (length is 0)
-            return;
-        char[] buffer = new char[length];
-        text.getCharacters_(buffer);
-
+    final Display display = browser.getDisplay();
+    bool top = frameID is webView.mainFrame().id;
+    if (top) {
         StatusTextEvent statusText = new StatusTextEvent(browser);
-        statusText.display = browser.getDisplay();
+        statusText.display = display;
         statusText.widget = browser;
-        statusText.text = new String(buffer);
-        for (int i = 0; i < statusTextListeners.length; i++)
-        {
+        statusText.text = url2;
+        for (int i = 0; i < statusTextListeners.length; i++) {
             statusTextListeners[i].changed(statusText);
         }
     }
 
-    void webView_setResizable (int sender, int visible)
-    {
+    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_setToolbarsVisible (int sender, int visible)
-    {
-        /* Note.  Webkit only emits the notification when the tool bar should be hidden. */
-        toolBar = visible !is 0;
+void webView_didFailProvisionalLoadWithError_forFrame(int /*long*/ sender, int /*long*/ error, int /*long*/ frame) {
+    if (frame is 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;
     }
 
-    void webView_mouseDidMoveOverElement_modifierFlags (int sender, int elementInformationID, int modifierFlags)
-    {
-        if (elementInformationID is 0)
-            return;
+    NSError nserror = new NSError(error);
+    int /*long*/ errorCode = nserror.code();
+    if (errorCode <= OS.NSURLErrorBadURL) {
+        NSString description = nserror.localizedDescription();
+        if (description !is null) {
+            String descriptionString = description.getString();
+            String urlString = null;
+            NSDictionary info = nserror.userInfo();
+            if (info !is null) {
+                NSString key = new NSString(OS.NSErrorFailingURLStringKey());
+                id id = info.valueForKey(key);
+                if (id !is null) {
+                    NSString url = new NSString(id);
+                    urlString = url.getString();
+                }
+            }
+            String message = urlString !is null ? urlString + "\n\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$
+            message += Compatibility.getMessage ("DWT_Page_Load_Failed", new Object[] {descriptionString}); //$NON-NLS-1$
+            MessageBox messageBox = new MessageBox(browser.getShell(), DWT.OK | DWT.ICON_ERROR);
+            messageBox.setMessage(message);
+            messageBox.open();
+        }
+    }
+}
+
+void webView_didFinishLoadForFrame(int /*long*/ sender, int /*long*/ frameID) {
+    hookDOMMouseListeners(frameID);
+    if (frameID is webView.mainFrame().id) {
+        hookDOMKeyListeners(frameID);
 
-        NSString key = NSString.StringWith(WebElementLinkURLKey);
-        NSDictionary elementInformation = new NSDictionary(elementInformationID);
-        id value = elementInformation.valueForKey(key);
-        if (value is null)
-        {
-            /* not currently over a link */
-            if (lastHoveredLinkURL is 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);
+        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 !is null) {
+            NSString title = dataSource.pageTitle();
+            if (title is 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);
+                                }
+                            }
+                        }
+                    );
+                }
             }
-            return;
+        }
+        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();
+
+    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();
+
+    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 is 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 is 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 is 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();
+    bool top = frameID is webView.mainFrame().id;
+    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);
+                    }
+                }
+            );
         }
 
-        NSString url = (new NSURL(value.id)).absoluteString();
-        int length = url.length();
-        String urlString;
-        if (length is 0)
-        {
-            urlString = ""; //$NON-NLS-1$
-        }
-        else
-        {
-            char[] buffer = new char[length];
-            url.getCharacters_(buffer);
-            urlString = new String(buffer);
-        }
-        if (urlString.opEquals(lastHoveredLinkURL))
-            return;
-
-        lastHoveredLinkURL = urlString;
         StatusTextEvent statusText = new StatusTextEvent(browser);
-        statusText.display = browser.getDisplay();
+        statusText.display = display;
         statusText.widget = browser;
-        statusText.text = urlString;
-        for (int i = 0; i < statusTextListeners.length; i++)
-        {
+        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_printFrameView (int sender, int frameViewID)
-    {
-        WebFrameView view = new WebFrameView(frameViewID);
-        bool viewPrint = view.documentViewShouldHandlePrint();
-        if (viewPrint)
-        {
-            view.printDocumentView();
-            return;
-        }
-        NSPrintInfo info = NSPrintInfo.sharedPrintInfo();
-        NSPrintOperation operation = view.printOperationWithPrintInfo(info);
-        if (operation !is null)
-            operation.runOperation();
-    }
+/* WebResourceLoadDelegate */
 
-    /* PolicyDelegate */
-
-    void webView_decidePolicyForMIMEType_request_frame_decisionListener (int sender, int type, int request, int frame, int listenerID)
-    {
-        bool canShow = WebView.canShowMIMEType(new NSString(type));
-        WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
-        if (canShow)
-        {
-            listener.use();
-        }
-        else
-        {
-            listener.download();
-        }
-    }
+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 is identifier) this.identifier = 0;
+}
 
-    void webView_decidePolicyForNavigationAction_request_frame_decisionListener (int sender, int actionInformation, int request, int frame,
-            int listenerID)
-    {
-        NSURL url = (new NSURLRequest(request)).URL();
-        WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
-        if (url is null)
-        {
-            /* indicates that a URL with an invalid format was specified */
-            listener.ignore();
-            return;
-        }
-        NSString s = url.absoluteString();
-        char[] buffer = new char[s.length()];
-        s.getCharacters_(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.opEquals(URI_FROMMEMORY))
-            url2 = ABOUT_BLANK;
+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 is identifier) this.identifier = 0;
+}
 
-        LocationEvent newEvent = new LocationEvent(browser);
-        newEvent.display = browser.getDisplay();
-        newEvent.widget = browser;
-        newEvent.location = url2;
-        newEvent.doit = true;
-        if (locationListeners !is null)
-        {
-            changingLocation = true;
-            for (int i = 0; i < locationListeners.length; i++)
-            {
-                locationListeners[i].changing(newEvent);
+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);
+                }
             }
-            changingLocation = false;
-        }
-        if (newEvent.doit)
-        {
-            listener.use();
-        }
-        else
-        {
-            listener.ignore();
-        }
-        if (html !is null && !browser.isDisposed())
-        {
-            String html = this.html;
-            this.html = null;
-            _setText(html);
-        }
-    }
-
-    void webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener (int sender, int actionInformation, int request, int frameName,
-            int listenerID)
-    {
-        WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
-        listener.use();
+        );
     }
 
-    void webView_unableToImplementPolicyWithError_frame (int sender, int error, int frame)
-    {
+    NSNumber identifier = NSNumber.numberWithInt(resourceCount++);
+    if (this.identifier is 0) {
+        WebDataSource dataSource = new WebDataSource(dataSourceID);
+        WebFrame frame = dataSource.webFrame();
+        if (frame.id is 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) {
+    return request;
+}
+
+/* handleNotification */
+
+void handleNotification(int /*long*/ notification) {    
+}
+
+/* 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 !is null) {
+        for (int i = 0; i < openWindowListeners.length; i++) {
+            openWindowListeners[i].open(newEvent);
+        }
+    }
+    WebView result = null;
+    Browser browser = null;
+    if (newEvent.browser !is null && newEvent.browser.webBrowser instanceof Safari) {
+        browser = newEvent.browser;
+    }
+    if (browser !is null && !browser.isDisposed()) {
+        result = ((Safari)browser.webBrowser).webView;
+        if (request !is 0) {
+            WebFrame mainFrame = webView.mainFrame();
+            mainFrame.loadRequest(new NSURLRequest(request));
+        }
     }
+    return result !is null ? result.id : 0;
+}
 
-    /* WebDownload */
+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 !is null) newEvent.location = location;
+    if (size !is 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 webView_setFrame(int /*long*/ sender, int /*long*/ frame) {
+    NSRect rect = new NSRect();
+    OS.memmove(rect, frame, NSRect.sizeof);
+    /* convert to DWT 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();
 
-    void download_decideDestinationWithSuggestedFilename (int downloadId, int filename)
-    {
-        NSString String = new NSString(filename);
-        char[] buffer = new char[String.length()];
-        String.getCharacters_(buffer);
-        String name = new String(buffer);
-        FileDialog dialog = new FileDialog(browser.getShell(), DWT.SAVE);
-        dialog.setText(DWT.getMessage("DWT_FileDownload")); //$NON-NLS-1$
-        dialog.setFileName(name);
-        String path = dialog.open();
-        NSURLDownload download = new NSURLDownload(downloadId);
-        if (path is null)
-        {
-            /* cancel pressed */
-            download.cancel();
-            return;
+    MessageBox messageBox = new MessageBox(browser.getShell(), DWT.OK | DWT.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(), DWT.OK | DWT.CANCEL | DWT.ICON_QUESTION);
+    messageBox.setText("Javascript");   //$NON-NLS-1$
+    messageBox.setMessage(text);
+    return messageBox.open() is DWT.OK ? 1 : 0;
+}
+
+void webView_runOpenPanelForFileButtonWithResultListener(int /*long*/ sender, int /*long*/ resultListenerID) {
+    FileDialog dialog = new FileDialog(browser.getShell(), DWT.NONE);
+    String result = dialog.open();
+    WebOpenPanelResultListener resultListener = new WebOpenPanelResultListener(resultListenerID);
+    if (result is 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(DWT.MenuDetect, event);
+    Menu menu = browser.getMenu();
+    if (!event.doit) return 0;
+    if (menu !is null && !menu.isDisposed()) {
+        if (event.x !is pt.x || event.y !is pt.y) {
+            menu.setLocation(event.x, event.y);
         }
-        download.setDestination(NSString.StringWith(path), true);
+        menu.setVisible(true);
+        return 0;
+    }
+    return defaultMenuItems;
+}
+
+void webView_setStatusBarVisible(int /*long*/ sender, bool 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 is 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, bool visible) {
+}
+
+void webView_setToolbarsVisible(int /*long*/ sender, bool 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 is 0) return;
+
+    NSString key = NSString.stringWith(WebElementLinkURLKey);
+    NSDictionary elementInformation = new NSDictionary(elementInformationID);
+    id value = elementInformation.valueForKey(key);
+    if (value is null) {
+        /* not currently over a link */
+        if (lastHoveredLinkURL is 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;
     }
 
-    /* DOMEventListener */
+    NSString url = new NSURL(value.id).absoluteString();
+    int length = (int)/*64*/url.length();
+    String urlString;
+    if (length is 0) {
+        urlString = ""; //$NON-NLS-1$
+    } else {
+        urlString = url.getString();
+    }
+    if (urlString.equals(lastHoveredLinkURL)) return;
 
-    void handleEvent (int evtId)
-    {
-        DOMEvent evt = new DOMEvent(evtId);
-        NSString String = evt.type();
-        char[] buffer = new char[String.length()];
-        String.getCharacters_(buffer);
-        String type = new String(buffer);
+    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);
+    }
+}
 
-        if (DOMEVENT_KEYDOWN.opEquals(type) || DOMEVENT_KEYUP.opEquals(type))
-        {
-            DOMKeyboardEvent event = new DOMKeyboardEvent(evtId);
+void webView_printFrameView (int /*long*/ sender, int /*long*/ frameViewID) {
+    WebFrameView view = new WebFrameView(frameViewID);
+    bool viewPrint = view.documentViewShouldHandlePrint();
+    if (viewPrint) {
+        view.printDocumentView();
+        return;
+    }
+    NSPrintInfo info = NSPrintInfo.sharedPrintInfo();
+    NSPrintOperation operation = view.printOperationWithPrintInfo(info);
+    if (operation !is null) operation.runOperation();
+}
+
+/* PolicyDelegate */
 
-            bool ctrl = event.ctrlKey();
-            bool shift = event.shiftKey();
-            bool alt = event.altKey();
-            bool meta = event.metaKey();
-            int keyCode = event.keyCode();
-            int charCode = event.charCode();
+void webView_decidePolicyForMIMEType_request_frame_decisionListener(int /*long*/ sender, int /*long*/ type, int /*long*/ request, int /*long*/ frame, int /*long*/ listenerID) {
+    bool 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 is 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;
 
-            Event keyEvent = new Event();
-            keyEvent.widget = browser;
-            if (DOMEVENT_KEYDOWN.opEquals(type))
-            {
-                keyEvent.type = DWT.KeyDown;
-            }
-            else
-            {
-                keyEvent.type = DWT.KeyUp;
-            }
-            keyEvent.keyCode = translateKey(keyCode);
-            keyEvent.character = cast(char) charCode;
-            keyEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
-            browser.notifyListeners(keyEvent.type, keyEvent);
-            if (!keyEvent.doit)
-            {
-                event.preventDefault();
-            }
-            return;
+    LocationEvent newEvent = new LocationEvent(browser);
+    newEvent.display = browser.getDisplay();
+    newEvent.widget = browser;
+    newEvent.location = url2;
+    newEvent.doit = true;
+    if (locationListeners !is null) {
+        changingLocation = true;
+        for (int i = 0; i < locationListeners.length; i++) {
+            locationListeners[i].changing(newEvent);
         }
+        changingLocation = false;
+    }
+    if (newEvent.doit) {
+        listener.use();
+    } else {
+        listener.ignore();
+    }
+    if (html !is 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();
+}
 
-        if (DOMEVENT_MOUSEWHEEL.opEquals(type))
-        {
-            DOMWheelEvent event = new DOMWheelEvent(evtId);
-            int clientX = event.clientX();
-            int clientY = event.clientY();
-            int delta = event.wheelDelta();
-            bool ctrl = event.ctrlKey();
-            bool shift = event.shiftKey();
-            bool alt = event.altKey();
-            bool meta = event.metaKey();
-            Event mouseEvent = new Event();
-            mouseEvent.type = DWT.MouseWheel;
-            mouseEvent.widget = browser;
-            mouseEvent.x = clientX;
-            mouseEvent.y = clientY;
-            mouseEvent.count = delta / 120;
-            mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
-            browser.notifyListeners(mouseEvent.type, mouseEvent);
-            return;
-        }
+void webView_unableToImplementPolicyWithError_frame(int /*long*/ sender, int /*long*/ error, int /*long*/ frame) {
+}
+
+/* WebDownload */
 
-        /* mouse event */
-
-        DOMMouseEvent event = new DOMMouseEvent(evtId);
+void download_decideDestinationWithSuggestedFilename(int /*long*/ downloadId, int /*long*/ filename) {
+    NSString string = new NSString(filename);
+    String name = string.getString();
+    FileDialog dialog = new FileDialog(browser.getShell(), DWT.SAVE);
+    dialog.setText(DWT.getMessage ("DWT_FileDownload")); //$NON-NLS-1$
+    dialog.setFileName(name);
+    String path = dialog.open();
+    NSURLDownload download = new NSURLDownload(downloadId);
+    if (path is null) {
+        /* cancel pressed */
+        download.cancel();
+        return;
+    }
+    download.setDestination(NSString.stringWith(path), true);
+}
 
-        int clientX = event.clientX();
-        int clientY = event.clientY();
-        int detail = event.detail();
-        int button = event.button();
+/* 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);
+
         bool ctrl = event.ctrlKey();
         bool shift = event.shiftKey();
         bool alt = event.altKey();
         bool meta = event.metaKey();
+        int keyCode = event.keyCode();
+        int charCode = event.charCode();
 
-        Event mouseEvent = new Event();
-        mouseEvent.widget = browser;
-        mouseEvent.x = clientX;
-        mouseEvent.y = clientY;
-        mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
-        if (DOMEVENT_MOUSEDOWN.opEquals(type))
-        {
-            mouseEvent.type = DWT.MouseDown;
-            mouseEvent.button = button + 1;
-            mouseEvent.count = detail;
+        Event keyEvent = new Event();
+        keyEvent.widget = browser;
+        if (DOMEVENT_KEYDOWN.equals(type)) {
+            keyEvent.type = DWT.KeyDown;
+        } else {
+            keyEvent.type = DWT.KeyUp;
+        }
+        keyEvent.keyCode = translateKey(keyCode);
+        keyEvent.character = (char)charCode;
+        keyEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
+        browser.notifyListeners(keyEvent.type, keyEvent);
+        if (!keyEvent.doit) {
+            event.preventDefault();
         }
-        else if (DOMEVENT_MOUSEUP.opEquals(type))
-        {
-            mouseEvent.type = DWT.MouseUp;
-            mouseEvent.button = button + 1;
-            mouseEvent.count = detail;
-            switch (mouseEvent.button)
-            {
-                case 1:
-                    mouseEvent.stateMask |= DWT.BUTTON1;
-                break;
-                case 2:
-                    mouseEvent.stateMask |= DWT.BUTTON2;
-                break;
-                case 3:
-                    mouseEvent.stateMask |= DWT.BUTTON3;
-                break;
-                case 4:
-                    mouseEvent.stateMask |= DWT.BUTTON4;
-                break;
-                case 5:
-                    mouseEvent.stateMask |= DWT.BUTTON5;
-                break;
-            }
+        return;
+    }
+
+    if (DOMEVENT_MOUSEWHEEL.equals(type)) {
+        DOMWheelEvent event = new DOMWheelEvent(evtId);
+        int clientX = event.clientX();
+        int clientY = event.clientY();
+        int delta = event.wheelDelta();
+        bool ctrl = event.ctrlKey();
+        bool shift = event.shiftKey();
+        bool alt = event.altKey();
+        bool meta = event.metaKey();
+        Event mouseEvent = new Event();
+        mouseEvent.type = DWT.MouseWheel;
+        mouseEvent.widget = browser;
+        mouseEvent.x = clientX; mouseEvent.y = clientY;
+        mouseEvent.count = delta / 120;
+        mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.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();
+    bool ctrl = event.ctrlKey();
+    bool shift = event.shiftKey();
+    bool alt = event.altKey();
+    bool meta = event.metaKey();
+
+    Event mouseEvent = new Event ();
+    mouseEvent.widget = browser;
+    mouseEvent.x = clientX; mouseEvent.y = clientY;
+    mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
+    if (DOMEVENT_MOUSEDOWN.equals (type)) {
+        mouseEvent.type = DWT.MouseDown;
+        mouseEvent.button = button + 1;
+        mouseEvent.count = detail;
+    } else if (DOMEVENT_MOUSEUP.equals (type)) {
+        mouseEvent.type = DWT.MouseUp;
+        mouseEvent.button = button + 1;
+        mouseEvent.count = detail;
+        switch (mouseEvent.button) {
+            case 1: mouseEvent.stateMask |= DWT.BUTTON1; break;
+            case 2: mouseEvent.stateMask |= DWT.BUTTON2; break;
+            case 3: mouseEvent.stateMask |= DWT.BUTTON3; break;
+            case 4: mouseEvent.stateMask |= DWT.BUTTON4; break;
+            case 5: mouseEvent.stateMask |= DWT.BUTTON5; break;
         }
-        else if (DOMEVENT_MOUSEMOVE.opEquals(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 is lastMouseMoveX && mouseEvent.y is lastMouseMoveY)
-                return;
-            mouseEvent.type = DWT.MouseMove;
-            lastMouseMoveX = mouseEvent.x;
-            lastMouseMoveY = mouseEvent.y;
-        }
+    } 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 is lastMouseMoveX && mouseEvent.y is lastMouseMoveY) return;
+        mouseEvent.type = DWT.MouseMove;
+        lastMouseMoveX = mouseEvent.x; lastMouseMoveY = mouseEvent.y;
+    }
 
-        browser.notifyListeners(mouseEvent.type, mouseEvent);
-        if (detail is 2 && DOMEVENT_MOUSEDOWN.opEquals(type))
-        {
-            mouseEvent = new Event();
-            mouseEvent.widget = browser;
-            mouseEvent.x = clientX;
-            mouseEvent.y = clientY;
-            mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
-            mouseEvent.type = DWT.MouseDoubleClick;
-            mouseEvent.button = button + 1;
-            mouseEvent.count = detail;
-            browser.notifyListeners(mouseEvent.type, mouseEvent);
-        }
+    browser.notifyListeners (mouseEvent.type, mouseEvent);
+    if (detail is 2 && DOMEVENT_MOUSEDOWN.equals (type)) {
+        mouseEvent = new Event ();
+        mouseEvent.widget = browser;
+        mouseEvent.x = clientX; mouseEvent.y = clientY;
+        mouseEvent.stateMask = (alt ? DWT.ALT : 0) | (ctrl ? DWT.CTRL : 0) | (shift ? DWT.SHIFT : 0) | (meta ? DWT.COMMAND : 0);
+        mouseEvent.type = DWT.MouseDoubleClick;
+        mouseEvent.button = button + 1;
+        mouseEvent.count = detail;
+        browser.notifyListeners (mouseEvent.type, mouseEvent);
     }
 }
+}