Mercurial > projects > dwt-mac
diff dwt/browser/Safari.d @ 0:380af2bdd8e5
Upload of whole dwt tree
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sat, 09 Aug 2008 17:00:02 +0200 |
parents | |
children | f565d3a95c0a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/browser/Safari.d Sat Aug 09 17:00:02 2008 +0200 @@ -0,0 +1,1566 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * Port to the D Programming language: + * Jacob Carlborg <jacob.carlborg@gmail.com> + *******************************************************************************/ +module dwt.browser.Safari; + +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.Callback; +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.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.NSString; +import dwt.internal.cocoa.NSURL; +import dwt.internal.cocoa.NSURLDownload; +import dwt.internal.cocoa.NSURLRequest; +import dwt.internal.cocoa.OS; +import dwt.internal.cocoa.DWTWebViewDelegate; +import dwt.internal.cocoa.WebDataSource; +import dwt.internal.cocoa.WebDocumentRepresentation; +import dwt.internal.cocoa.WebFrame; +import dwt.internal.cocoa.WebFrameView; +import dwt.internal.cocoa.WebOpenPanelResultListener; +import dwt.internal.cocoa.WebPolicyDecisionListener; +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; +import dwt.widgets.FileDialog; +import dwt.widgets.Listener; +import dwt.widgets.Menu; +import dwt.widgets.MessageBox; +import dwt.widgets.Shell; + +import Math = tango.math.Math; + +import dwt.dwthelper.Runnable; + +class Safari : WebBrowser +{ + WebView webView; + DWTWebViewDelegate delegatee; + int jniRef; + bool changingLocation; + String lastHoveredLinkURL; + String html; + int identifier; + int resourceCount; + String url = ""; + Point location; + Point size; + bool statusBar = true, toolBar = true, ignoreDispose; + int lastMouseMoveX, lastMouseMoveY; + //TEMPORARY CODE + // 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$ + + /* 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 this () + { + NativeClearSessions = new class Runnable + { + public void run () + { + NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage(); + NSArray cookies = storage.cookies(); + int count = cookies.count(); + + for (int i = 0; i < count; i++) + { + NSHTTPCookie cookie = new NSHTTPCookie(cookies.objectAtIndex(i)); + if (cookie.isSessionOnly()) + { + storage.deleteCookie(cookie); + } + } + } + }; + } + + 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(); + + 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; + } + + 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; + } + } + + void webView_didFinishLoadForFrame (int sender, int frameID) + { + hookDOMMouseListeners(frameID); + if (frameID is webView.mainFrame().id) + { + hookDOMKeyListeners(frameID); + + 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); + } + } + }); + } + } + } + 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); + + type = NSString.StringWith(DOMEVENT_KEYUP); + document.addEventListener_listener_useCapture(type, delegatee, false); + } + + void hookDOMMouseListeners (int frameID) + { + WebFrame frame = new WebFrame(frameID); + DOMDocument document = frame.DOMDocument(); + + 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); + + type = NSString.StringWith(DOMEVENT_MOUSEMOVE); + document.addEventListener_listener_useCapture(type, delegatee, false); + + type = NSString.StringWith(DOMEVENT_MOUSEWHEEL); + document.addEventListener_listener_useCapture(type, delegatee, false); + } + + 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); + } + } + } + + 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; + // } + } + + 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; + + const Display display = browser.getDisplay(); + bool top = frameID is webView.mainFrame().id; + if (top) + { + /* reset resource status variables */ + resourceCount = 0; + this.url = url2; + + 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); + } + }); + } + + 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); + } + } + + /* WebResourceLoadDelegate */ + + void webView_resource_didFinishLoadingFromDataSource (int sender, int identifier, int dataSource) + { + /* + * Feature on Safari. The identifier is used here as a marker for the events + * related to the top frame and the URL changes related to that top frame as + * they should appear on the location bar of a browser. It is expected to reset + * the identifier to 0 when the event didFinishLoadingFromDataSource related to + * the identifierForInitialRequest event is received. 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_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; + } + + 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); + } + }); + } + + 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; + } + + 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); + + 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); + + StatusTextEvent statusText = new StatusTextEvent(browser); + statusText.display = browser.getDisplay(); + statusText.widget = browser; + statusText.text = new String(buffer); + for (int i = 0; i < statusTextListeners.length; i++) + { + statusTextListeners[i].changed(statusText); + } + } + + void webView_setResizable (int sender, int visible) + { + } + + 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_mouseDidMoveOverElement_modifierFlags (int sender, int elementInformationID, int 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; + } + + 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.widget = browser; + statusText.text = urlString; + for (int i = 0; i < statusTextListeners.length; i++) + { + statusTextListeners[i].changed(statusText); + } + } + + 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(); + } + + /* 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_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; + + 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 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) + { + } + + /* WebDownload */ + + 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; + } + download.setDestination(NSString.StringWith(path), true); + } + + /* DOMEventListener */ + + 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); + + if (DOMEVENT_KEYDOWN.opEquals(type) || DOMEVENT_KEYUP.opEquals(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 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; + } + + 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; + } + + /* 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.opEquals(type)) + { + mouseEvent.type = DWT.MouseDown; + mouseEvent.button = button + 1; + mouseEvent.count = detail; + } + 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; + } + } + 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; + } + + 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); + } + } +}