Package org.eclipse.swt.browser

Source Code of org.eclipse.swt.browser.Browser$WindowScriptObjectListener

/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
// Modified by Google
package org.eclipse.swt.browser;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.Callback;
import org.eclipse.swt.internal.carbon.*;
import org.eclipse.swt.widgets.*;

/**
* Instances of this class implement the browser user interface
* metaphor.  It allows the user to visualize and navigate through
* HTML documents.
* <p>
* Note that although this class is a subclass of <code>Composite</code>,
* it does not make sense to set a layout on it.
* </p><p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
* </p>
*
* @since 3.0
*/
public class Browser extends Composite {
 
  /* Package Name */
  static final String PACKAGE_PREFIX = "org.eclipse.swt.browser."; //$NON-NLS-1$
  static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$
  // GOOGLE: patched in from https://bugs.eclipse.org/bugs/show_bug.cgi?id=161259
  static final String CLEAR_GRAB_BIT = "org.eclipse.swt.internal.carbon.clearGrabBit"; //$NON-NLS-1$
  static final String BROWSER_WINDOW = "org.eclipse.swt.browser.Browser.Window"; //$NON-NLS-1$
  static final int MAX_PROGRESS = 100;
 
  /* External Listener management */
  CloseWindowListener[] closeWindowListeners = new CloseWindowListener[0];
  LocationListener[] locationListeners = new LocationListener[0];
  OpenWindowListener[] openWindowListeners = new OpenWindowListener[0];
  ProgressListener[] progressListeners = new ProgressListener[0];
  StatusTextListener[] statusTextListeners = new StatusTextListener[0];
  TitleListener[] titleListeners = new TitleListener[0];
  VisibilityWindowListener[] visibilityWindowListeners = new VisibilityWindowListener[0];
 
  static Callback Callback3, Callback7;

  /* Objective-C WebView delegate */
  int delegate;
 
  /* Carbon HIView handle */
  int webViewHandle;
 
  boolean changingLocation;
  String html;
  int identifier;
  int resourceCount;
  String url = "";
  Point location;
  Point size;
  boolean statusBar = true, toolBar = true, ignoreDispose;
  //TEMPORARY CODE
//  boolean doit;

  static final int MIN_SIZE = 16;

/**
* Constructs a new instance of this class given its parent
* and a style value describing its behavior and appearance.
* <p>
* The style value is either one of the style constants defined in
* class <code>SWT</code> which is applicable to instances of this
* class, or must be built by <em>bitwise OR</em>'ing together
* (that is, using the <code>int</code> "|" operator) two or more
* of those <code>SWT</code> style constants. The class description
* lists the style constants that are applicable to the class.
* Style bits are also inherited from superclasses.
* </p>
*
* @param parent a widget which will be the parent of the new instance (cannot be null)
* @param style the style of widget to construct
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
* </ul>
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
* </ul>
* @exception SWTError <ul>
*    <li>ERROR_NO_HANDLES if a handle could not be obtained for browser creation</li>
* </ul>
*
* @see Widget#getStyle
*
* @since 3.0
*/
public Browser(Composite parent, int style) {
  super(parent, style);

  /*
  * Note.  Loading the webkit bundle on Jaguar causes a crash.
  * The workaround is to detect any OS prior to 10.30 and fail
  * without crashing.
  */
  if (OS.VERSION < 0x1030) {
    dispose();
    SWT.error(SWT.ERROR_NO_HANDLES);
  }
  int outControl[] = new int[1];
  try {
    WebKit.HIWebViewCreate(outControl);
  } catch (UnsatisfiedLinkError e) {
    dispose();
    SWT.error(SWT.ERROR_NO_HANDLES);
  }
  webViewHandle = outControl[0];
  if (webViewHandle == 0) {
    dispose();
    SWT.error(SWT.ERROR_NO_HANDLES);   
  }
  Display display = getDisplay();
  display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), this});
  // GOOGLE: patched in from https://bugs.eclipse.org/bugs/show_bug.cgi?id=161259
  setData(CLEAR_GRAB_BIT, null);

  /*
  * Bug in Safari.  For some reason, every application must contain
  * a visible window that has never had a WebView or mouse move events
  * are not delivered.  This seems to happen after a browser has been
  * either hidden or disposed in any window.  The fix is to create a
  * single transparent overlay window that is disposed when the display
  * is disposed.
  */
  if (display.getData(BROWSER_WINDOW) == null) {
    Rect bounds = new Rect ();
    OS.SetRect (bounds, (short) 0, (short) 0, (short) 1, (short) 1);
    final int[] outWindow = new int[1];
    OS.CreateNewWindow(OS.kOverlayWindowClass, 0, bounds, outWindow);
    OS.ShowWindow(outWindow[0]);
    display.disposeExec(new Runnable() {
      public void run() {
        if (outWindow[0] != 0) {
          OS.DisposeWindow(outWindow[0]);
        }
        outWindow[0] = 0;
      }
    });
    display.setData(BROWSER_WINDOW, outWindow);
  }
 
  /*
   * Bug in Safari. The WebView does not receive mouse and key events when it is added
   * to a visible top window.  It is assumed that Safari hooks its own event listener
   * when the top window emits the kEventWindowShown event. The workaround is to send a
   * fake kEventWindowShown event to the top window after the WebView has been added
   * to the HIView (after the top window is visible) to give Safari a chance to hook
   * events.
   */
  int window = OS.GetControlOwner(handle);
  if (OS.HIVIEW) {
    int[] contentView = new int[1];
    OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView);
    OS.HIViewAddSubview(contentView[0], webViewHandle);
    OS.HIViewChangeFeatures(webViewHandle, OS.kHIViewFeatureIsOpaque, 0);
  } else {
    OS.HIViewAddSubview(handle, webViewHandle);
  }
  OS.HIViewSetVisible(webViewHandle, true)
  if (getShell().isVisible()) {
    int[] showEvent = new int[1];
    OS.CreateEvent(0, OS.kEventClassWindow, OS.kEventWindowShown, 0.0, OS.kEventAttributeUserEvent, showEvent);
    OS.SetEventParameter(showEvent[0], OS.kEventParamDirectObject, OS.typeWindowRef, 4, new int[] {OS.GetControlOwner(handle)});
    OS.SendEventToEventTarget(showEvent[0], OS.GetWindowEventTarget(window));
    if (showEvent[0] != 0) OS.ReleaseEvent(showEvent[0]);
  }

  final int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  /*
  * This code is intentionally commented. Setting a group name is the right thing
  * to do in order to avoid multiple open window requests. For some reason, Safari
  * crashes when requested to reopen the same window if that window was previously
  * closed. This may be because that window was not correctly closed.
  */ 
//  String groupName = "MyDocument"; //$NON-NLS-1$
//  int length = groupName.length();
//  char[] buffer = new char[length];
//  groupName.getChars(0, length, buffer, 0);
//  int groupNameString = OS.CFStringCreateWithCharacters(0, buffer, length);
//  // [webView setGroupName:@"MyDocument"];
//  WebKit.objc_msgSend(webView, WebKit.S_setGroupName, groupNameString);
//  OS.CFRelease(groupNameString);
 
  final int notificationCenter = WebKit.objc_msgSend(WebKit.C_NSNotificationCenter, WebKit.S_defaultCenter);

  Listener listener = new Listener() {
    public void handleEvent(Event e) {
      switch (e.type) {
        case SWT.Dispose: {
          /* make this handler run after other dispose listeners */
          if (ignoreDispose) {
            ignoreDispose = false;
            break;
          }
          ignoreDispose = true;
          notifyListeners (e.type, e);
          e.type = SWT.NONE;

          Shell shell = getShell();
          shell.removeListener(SWT.Resize, this);
          shell.removeListener(SWT.Show, this);
          shell.removeListener(SWT.Hide, this);
          Control c = Browser.this;
          do {
            c.removeListener(SWT.Show, this);
            c.removeListener(SWT.Hide, this);
            c = c.getParent();
          } while (c != shell);

          e.display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), null});

          WebKit.objc_msgSend(webView, WebKit.S_setFrameLoadDelegate, 0);
          WebKit.objc_msgSend(webView, WebKit.S_setResourceLoadDelegate, 0);
          WebKit.objc_msgSend(webView, WebKit.S_setUIDelegate, 0);
          WebKit.objc_msgSend(webView, WebKit.S_setPolicyDelegate, 0);
          WebKit.objc_msgSend(notificationCenter, WebKit.S_removeObserver, delegate);
         
          WebKit.objc_msgSend(delegate, WebKit.S_release);
          if (OS.HIVIEW) OS.DisposeControl(webViewHandle);
          html = null;
          break;
        }
        case SWT.Hide: {
          /*
          * Bug on Safari. The web view cannot be obscured by other views above it.
          * This problem is specified in the apple documentation for HiWebViewCreate.
          * The workaround is to hook Hide and Show events on the browser's parents
          * and set its size to 0 in Hide and to restore its size in Show.
          */
          CGRect bounds = new CGRect();
          bounds.x = bounds.y = -MIN_SIZE;
          bounds.width = bounds.height = MIN_SIZE;
          OS.HIViewSetFrame(webViewHandle, bounds);
          break;
        }
        case SWT.Show: {
          /*
          * Do not update size when it is not visible. Note that isVisible()
          * cannot be used because SWT.Show is sent before the widget is
          * actually visible.
          */
          Shell shell = getShell();
          Composite parent = Browser.this;
          while (parent != shell && (parent.getVisible() || parent == e.widget)) {
            parent = parent.getParent();
          }
          if (!(parent.getVisible() || parent == e.widget)) return;

          /*
          * Bug on Safari. The web view cannot be obscured by other views above it.
          * This problem is specified in the apple documentation for HiWebViewCreate.
          * The workaround is to hook Hide and Show events on the browser's parents
          * and set its size to 0 in Hide and to restore its size in Show.
          */
          CGRect bounds = new CGRect();
          if (OS.HIVIEW) {
            OS.HIViewGetBounds(handle, bounds);
            int[] contentView = new int[1];
            OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(handle)), OS.kHIViewWindowContentID(), contentView);
            OS.HIViewConvertRect(bounds, handle, contentView[0]);
          } else {
            OS.HIViewGetFrame(handle, bounds);
          }
          /*
          * Bug in Safari.  For some reason, the web view will display incorrectly or
          * blank depending on its contents, if its size is set to a value smaller than
          * MIN_SIZE. It will not display properly even after the size is made larger.
          * The fix is to avoid setting sizes smaller than MIN_SIZE.
          */
          if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE;
          if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE;
          OS.HIViewSetFrame(webViewHandle, bounds);
          break;
        }
        case SWT.Resize: {
          /* Do not update size when it is not visible */
          if (!isVisible()) return;
          /*
          * Bug on Safari. Resizing the height of a Shell containing a Browser at
          * a fixed location causes the Browser to redraw at a wrong location.
          * The web view is a HIView container that internally hosts
          * a Cocoa NSView that uses a coordinates system with the origin at the
          * bottom left corner of a window instead of the coordinates system used
          * in Carbon that starts at the top left corner. The workaround is to
          * reposition the web view every time the Shell of the Browser is resized.
          */
          CGRect bounds = new CGRect();
          if (OS.HIVIEW) {
            OS.HIViewGetBounds(handle, bounds);
            int[] contentView = new int[1];
            OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(handle)), OS.kHIViewWindowContentID(), contentView);
            OS.HIViewConvertRect(bounds, handle, contentView[0]);
          } else {
            OS.HIViewGetFrame(handle, bounds);
          }
          /*
          * Bug in Safari.  For some reason, the web view will display incorrectly or
          * blank depending on its contents, if its size is set to a value smaller than
          * MIN_SIZE. It will not display properly even after the size is made larger.
          * The fix is to avoid setting sizes smaller than MIN_SIZE.
          */
          if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE;
          if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE;
          if (e.widget == getShell()) {
            bounds.x++;
            /* Note that the bounds needs to change */
            OS.HIViewSetFrame(webViewHandle, bounds);
            bounds.x--;
          }
          OS.HIViewSetFrame(webViewHandle, bounds);
          break;
        }
      }
    }
  };
  addListener(SWT.Dispose, listener);
  addListener(SWT.Resize, listener);
  Shell shell = getShell();
  shell.addListener(SWT.Resize, listener);
  shell.addListener(SWT.Show, listener);
  shell.addListener(SWT.Hide, listener);
  Control c = this;
  do {
    c.addListener(SWT.Show, listener);
    c.addListener(SWT.Hide, listener);
    c = c.getParent();
  } while (c != shell);
 
  if (Callback3 == null) Callback3 = new Callback(this.getClass(), "eventProc3", 3); //$NON-NLS-1$
  int callback3Address = Callback3.getAddress();
  if (callback3Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);

  int[] mask = new int[] {
    OS.kEventClassKeyboard, OS.kEventRawKeyDown,
    OS.kEventClassControl, OS.kEventControlDraw,
    OS.kEventClassTextInput, OS.kEventTextInputUnicodeForKeyEvent,
  };
  int controlTarget = OS.GetControlEventTarget(webViewHandle);
  OS.InstallEventHandler(controlTarget, callback3Address, mask.length / 2, mask, webViewHandle, null);

  if (Callback7 == null) Callback7 = new Callback(this.getClass(), "eventProc7", 7); //$NON-NLS-1$
  int callback7Address = Callback7.getAddress();
  if (callback7Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
 
  // delegate = [[WebResourceLoadDelegate alloc] init eventProc];
  delegate = WebKit.objc_msgSend(WebKit.C_WebKitDelegate, WebKit.S_alloc);
  delegate = WebKit.objc_msgSend(delegate, WebKit.S_initWithProc, callback7Address, webViewHandle);
       
  // [webView setFrameLoadDelegate:delegate];
  WebKit.objc_msgSend(webView, WebKit.S_setFrameLoadDelegate, delegate);
   
  // [webView setResourceLoadDelegate:delegate];
  WebKit.objc_msgSend(webView, WebKit.S_setResourceLoadDelegate, delegate);

  // [webView setUIDelegate:delegate];
  WebKit.objc_msgSend(webView, WebKit.S_setUIDelegate, delegate);
 
  /* register delegate for all notifications sent out from webview */
  WebKit.objc_msgSend(notificationCenter, WebKit.S_addObserver_selector_name_object, delegate, WebKit.S_handleNotification, 0, webView);
 
  // [webView setPolicyDelegate:delegate];
  WebKit.objc_msgSend(webView, WebKit.S_setPolicyDelegate, delegate);

  // [webView setDownloadDelegate:delegate];
  WebKit.objc_msgSend(webView, WebKit.S_setDownloadDelegate, delegate);
}

/**
* Clears all session cookies from all current Browser instances.
*
* @since 3.2
*/
public static void clearSessions () {
  int storage = WebKit.objc_msgSend (WebKit.C_NSHTTPCookieStorage, WebKit.S_sharedHTTPCookieStorage);
  int cookies = WebKit.objc_msgSend (storage, WebKit.S_cookies);
  int count = WebKit.objc_msgSend (cookies, WebKit.S_count);
  for (int i = 0; i < count; i++) {
    int cookie = WebKit.objc_msgSend (cookies, WebKit.S_objectAtIndex, i);
    boolean isSession = WebKit.objc_msgSend (cookie, WebKit.S_isSessionOnly) != 0;
    if (isSession) {
      WebKit.objc_msgSend (storage, WebKit.S_deleteCookie, cookie);
    }
  }
}

static int eventProc3(int nextHandler, int theEvent, int userData) {
  Widget widget = Display.getCurrent().findWidget(userData);
  if (widget instanceof Browser)
    return ((Browser)widget).handleCallback(nextHandler, theEvent);
  return OS.eventNotHandledErr;
}

static int eventProc7(int webview, int userData, int selector, int arg0, int arg1, int arg2, int arg3) {
  Widget widget = Display.getCurrent().findWidget(userData);
  if (widget instanceof Browser)
    return ((Browser)widget).handleCallback(selector, arg0, arg1, arg2, arg3);
  return 0;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when the window hosting the receiver should be closed.
* <p>
* This notification occurs when a javascript command such as
* <code>window.close</code> gets executed by a <code>Browser</code>.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addCloseWindowListener(CloseWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT)
  CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length + 1];
  System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, closeWindowListeners.length);
  closeWindowListeners = newCloseWindowListeners;
  closeWindowListeners[closeWindowListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when the current location has changed or is about to change.
* <p>
* This notification typically occurs when the application navigates
* to a new location with {@link #setUrl(String)} or when the user
* activates a hyperlink.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addLocationListener(LocationListener listener) {
  checkWidget();
  if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
  LocationListener[] newLocationListeners = new LocationListener[locationListeners.length + 1];
  System.arraycopy(locationListeners, 0, newLocationListeners, 0, locationListeners.length);
  locationListeners = newLocationListeners;
  locationListeners[locationListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when a new window needs to be created.
* <p>
* This notification occurs when a javascript command such as
* <code>window.open</code> gets executed by a <code>Browser</code>.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addOpenWindowListener(OpenWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length + 1];
  System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, openWindowListeners.length);
  openWindowListeners = newOpenWindowListeners;
  openWindowListeners[openWindowListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when a progress is made during the loading of the current
* URL or when the loading of the current URL has been completed.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addProgressListener(ProgressListener listener) {
  checkWidget();
  if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
  ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length + 1];
  System.arraycopy(progressListeners, 0, newProgressListeners, 0, progressListeners.length);
  progressListeners = newProgressListeners;
  progressListeners[progressListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when the status text is changed.
* <p>
* The status text is typically displayed in the status bar of
* a browser application.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addStatusTextListener(StatusTextListener listener) {
  checkWidget();
  if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
  StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length + 1];
  System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, statusTextListeners.length);
  statusTextListeners = newStatusTextListeners;
  statusTextListeners[statusTextListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when the title of the current document is available
* or has changed.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addTitleListener(TitleListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  TitleListener[] newTitleListeners = new TitleListener[titleListeners.length + 1];
  System.arraycopy(titleListeners, 0, newTitleListeners, 0, titleListeners.length);
  titleListeners = newTitleListeners;
  titleListeners[titleListeners.length - 1] = listener;
}

/**  
* Adds the listener to the collection of listeners who will be
* notified when a window hosting the receiver needs to be displayed
* or hidden.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addVisibilityWindowListener(VisibilityWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length + 1];
  System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, visibilityWindowListeners.length);
  visibilityWindowListeners = newVisibilityWindowListeners;
  visibilityWindowListeners[visibilityWindowListeners.length - 1] = listener;
}

/**
* Navigate to the previous session history item.
*
* @return <code>true</code> if the operation was successful and <code>false</code> otherwise
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see #forward
*
* @since 3.0
*/
public boolean back() {
  checkWidget();
  html = null;
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  return WebKit.objc_msgSend(webView, WebKit.S_goBack) != 0;
}

protected void checkSubclass () {
  String name = getClass().getName();
  int index = name.lastIndexOf('.');
  if (!name.substring(0, index + 1).equals(PACKAGE_PREFIX)) {
    SWT.error(SWT.ERROR_INVALID_SUBCLASS);
  }
}

/**
* Execute the specified script.
*
* <p>
* Execute a script containing javascript commands in the context of the current document.
*
* @param script the script with javascript commands
* @return <code>true</code> if the operation was successful and <code>false</code> otherwise
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the script is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.1
*/
public boolean execute(String script) {
  checkWidget();
  if (script == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);

  int length = script.length();
  char[] buffer = new char[length];
  script.getChars(0, length, buffer, 0);
  int string = OS.CFStringCreateWithCharacters(0, buffer, length);

  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  int value = WebKit.objc_msgSend(webView, WebKit.S_stringByEvaluatingJavaScriptFromString, string);
  OS.CFRelease(string);
  return value != 0;
}

/**
* Navigate to the next session history item.
*
* @return <code>true</code> if the operation was successful and <code>false</code> otherwise
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see #back
*
* @since 3.0
*/
public boolean forward() {
  checkWidget();
  html = null;
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  return WebKit.objc_msgSend(webView, WebKit.S_goForward) != 0;
}

/**
* Returns the current URL.
*
* @return the current URL or an empty <code>String</code> if there is no current URL
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see #setUrl
*
* @since 3.0
*/
public String getUrl() {
  checkWidget();
  return url;
}

int handleCallback(int nextHandler, int theEvent) {
  int eventKind = OS.GetEventKind(theEvent);
  switch (eventKind) {
    case OS.kEventControlDraw: {         
      /*
      * Bug on Safari. The web view cannot be obscured by other views above it.
      * This problem is specified in the apple documentation for HiWebViewCreate.
      * The workaround is to don't draw the web view when it is not visible.
      */
      if (!isVisible ()) return OS.noErr;
           
      /*
      * GOOGLE: HACK - SWT does not properly push repaint events back to
      * WebKit, so we actually naively tell webkit to repaint it's entire
      * client area.
      */
      setNeedsDisplay(true);           
     
      break;
    }
    case OS.kEventRawKeyDown: {
      /*
      * Bug in Safari. The WebView blocks the propagation of certain Carbon events
      * such as kEventRawKeyDown. On the Mac, Carbon events propagate from the
      * Focus Target Handler to the Control Target Handler, Window Target and finally
      * the Application Target Handler. It is assumed that WebView hooks its events
      * on the Window Target and does not pass kEventRawKeyDown to the next handler.
      * Since kEventRawKeyDown events never make it to the Application Target Handler,
      * the Application Target Handler never gets to emit kEventTextInputUnicodeForKeyEvent
      * used by SWT to send a SWT.KeyDown event.
      * The workaround is to hook kEventRawKeyDown on the Control Target Handler which gets
      * called before the WebView hook on the Window Target Handler. Then, forward this event
      * directly to the Application Target Handler. Note that if in certain conditions Safari
      * does not block the kEventRawKeyDown, then multiple kEventTextInputUnicodeForKeyEvent
      * events might be generated as a result of this workaround.
      */
      //TEMPORARY CODE
//      doit = false;
//      OS.SendEventToEventTarget(theEvent, OS.GetApplicationEventTarget());
//      if (!doit) return OS.noErr;
      break;
    }
    case OS.kEventTextInputUnicodeForKeyEvent: {
      /*
      * Note.  This event is received from the Window Target therefore after it was received
      * by the Focus Target. The SWT.KeyDown event is sent by SWT on the Focus Target. If it
      * is received here, then the SWT.KeyDown doit flag must have been left to the value
      * true.  For package visibility reasons we cannot access the doit flag directly.
      *
      * Sequence of events when the user presses a key down
      *
      * .Control Target - kEventRawKeyDown
      *   .forward to ApplicationEventTarget
      *     .Focus Target kEventTextInputUnicodeForKeyEvent - SWT emits SWT.KeyDown -
      *       blocks further propagation if doit false. Browser does not know directly about
      *       the doit flag value.
      *       .Window Target kEventTextInputUnicodeForKeyEvent - if received, Browser knows
      *       SWT.KeyDown is not blocked and event should be sent to WebKit
      *  Return from Control Target - kEventRawKeyDown: let the event go to WebKit if doit true
      *  (eventNotHandledErr) or stop it (noErr).
      */
      //TEMPORARY CODE
//      doit = true;
      break;
    }
  }
  return OS.eventNotHandledErr;
}

/* Here we dispatch all WebView upcalls. */
int handleCallback(int selector, int arg0, int arg1, int arg2, int arg3) {
  int ret = 0;
  // for meaning of selector see WebKitDelegate methods in webkit.c
  switch (selector) {
    case 1: didFailProvisionalLoadWithError(arg0, arg1); break;
    case 2: didFinishLoadForFrame(arg0); break;
    case 3: didReceiveTitle(arg0, arg1); break;
    case 4: didStartProvisionalLoadForFrame(arg0); break;
    case 5: didFinishLoadingFromDataSource(arg0, arg1); break;
    case 6: didFailLoadingWithError(arg0, arg1, arg2); break;
    case 7: ret = identifierForInitialRequest(arg0, arg1); break;
    case 8: ret = willSendRequest(arg0, arg1, arg2, arg3); break;
    case 9: handleNotification(arg0); break;
    case 10: didCommitLoadForFrame(arg0); break;
    case 11: ret = createWebViewWithRequest(arg0); break;
    case 12: webViewShow(arg0); break;
    case 13: setFrame(arg0); break;
    case 14: webViewClose(); break;
    case 15: ret = contextMenuItemsForElement(arg0, arg1); break;
    case 16: setStatusBarVisible(arg0); break;
    case 17: setResizable(arg0); break;
    case 18: setToolbarsVisible(arg0); break;
    case 19: decidePolicyForMIMEType(arg0, arg1, arg2, arg3); break;
    case 20: decidePolicyForNavigationAction(arg0, arg1, arg2, arg3); break;
    case 21: decidePolicyForNewWindowAction(arg0, arg1, arg2, arg3); break;
    case 22: unableToImplementPolicyWithError(arg0, arg1); break;
    case 23: setStatusText(arg0); break;
    case 24: webViewFocus(); break;
    case 25: webViewUnfocus(); break;
    case 26: runJavaScriptAlertPanelWithMessage(arg0); break;
    case 27: ret = runJavaScriptConfirmPanelWithMessage(arg0); break;
    case 28: runOpenPanelForFileButtonWithResultListener(arg0); break;
    case 29: decideDestinationWithSuggestedFilename(arg0, arg1); break;
        // GOOGLE
    case 99: fireWindowScriptObjectListeners(arg0); break;
  }
  return ret;
}

/**
* Returns <code>true</code> if the receiver can navigate to the
* previous session history item, and <code>false</code> otherwise.
*
* @return the receiver's back command enabled state
*
* @exception SWTException <ul>
*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #back
*/
public boolean isBackEnabled() {
  checkWidget();
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  return WebKit.objc_msgSend(webView, WebKit.S_canGoBack) != 0;
}

/**
* Returns <code>true</code> if the receiver can navigate to the
* next session history item, and <code>false</code> otherwise.
*
* @return the receiver's forward command enabled state
*
* @exception SWTException <ul>
*    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
*    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #forward
*/
public boolean isForwardEnabled() {
  checkWidget();
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  return WebKit.objc_msgSend(webView, WebKit.S_canGoForward) != 0;
}

/**
* Refresh the current page.
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void refresh() {
  checkWidget();
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  WebKit.objc_msgSend(webView, WebKit.S_reload, 0);
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when the window hosting the receiver should be closed.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeCloseWindowListener(CloseWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (closeWindowListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < closeWindowListeners.length; i++) {
    if (listener == closeWindowListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (closeWindowListeners.length == 1) {
    closeWindowListeners = new CloseWindowListener[0];
    return;
  }
  CloseWindowListener[] newCloseWindowListeners = new CloseWindowListener[closeWindowListeners.length - 1];
  System.arraycopy(closeWindowListeners, 0, newCloseWindowListeners, 0, index);
  System.arraycopy(closeWindowListeners, index + 1, newCloseWindowListeners, index, closeWindowListeners.length - index - 1);
  closeWindowListeners = newCloseWindowListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when the current location is changed or about to be changed.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeLocationListener(LocationListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (locationListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < locationListeners.length; i++) {
    if (listener == locationListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (locationListeners.length == 1) {
    locationListeners = new LocationListener[0];
    return;
  }
  LocationListener[] newLocationListeners = new LocationListener[locationListeners.length - 1];
  System.arraycopy(locationListeners, 0, newLocationListeners, 0, index);
  System.arraycopy(locationListeners, index + 1, newLocationListeners, index, locationListeners.length - index - 1);
  locationListeners = newLocationListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when a new window needs to be created.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeOpenWindowListener(OpenWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (openWindowListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < openWindowListeners.length; i++) {
    if (listener == openWindowListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (openWindowListeners.length == 1) {
    openWindowListeners = new OpenWindowListener[0];
    return;
  }
  OpenWindowListener[] newOpenWindowListeners = new OpenWindowListener[openWindowListeners.length - 1];
  System.arraycopy(openWindowListeners, 0, newOpenWindowListeners, 0, index);
  System.arraycopy(openWindowListeners, index + 1, newOpenWindowListeners, index, openWindowListeners.length - index - 1);
  openWindowListeners = newOpenWindowListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when a progress is made during the loading of the current
* URL or when the loading of the current URL has been completed.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeProgressListener(ProgressListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (progressListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < progressListeners.length; i++) {
    if (listener == progressListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (progressListeners.length == 1) {
    progressListeners = new ProgressListener[0];
    return;
  }
  ProgressListener[] newProgressListeners = new ProgressListener[progressListeners.length - 1];
  System.arraycopy(progressListeners, 0, newProgressListeners, 0, index);
  System.arraycopy(progressListeners, index + 1, newProgressListeners, index, progressListeners.length - index - 1);
  progressListeners = newProgressListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when the status text is changed.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeStatusTextListener(StatusTextListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (statusTextListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < statusTextListeners.length; i++) {
    if (listener == statusTextListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (statusTextListeners.length == 1) {
    statusTextListeners = new StatusTextListener[0];
    return;
  }
  StatusTextListener[] newStatusTextListeners = new StatusTextListener[statusTextListeners.length - 1];
  System.arraycopy(statusTextListeners, 0, newStatusTextListeners, 0, index);
  System.arraycopy(statusTextListeners, index + 1, newStatusTextListeners, index, statusTextListeners.length - index - 1);
  statusTextListeners = newStatusTextListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when the title of the current document is available
* or has changed.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeTitleListener(TitleListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (titleListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < titleListeners.length; i++) {
    if (listener == titleListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (titleListeners.length == 1) {
    titleListeners = new TitleListener[0];
    return;
  }
  TitleListener[] newTitleListeners = new TitleListener[titleListeners.length - 1];
  System.arraycopy(titleListeners, 0, newTitleListeners, 0, index);
  System.arraycopy(titleListeners, index + 1, newTitleListeners, index, titleListeners.length - index - 1);
  titleListeners = newTitleListeners;
}

/**  
* Removes the listener from the collection of listeners who will
* be notified when a window hosting the receiver needs to be displayed
* or hidden.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeVisibilityWindowListener(VisibilityWindowListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (visibilityWindowListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < visibilityWindowListeners.length; i++) {
    if (listener == visibilityWindowListeners[i]){
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (visibilityWindowListeners.length == 1) {
    visibilityWindowListeners = new VisibilityWindowListener[0];
    return;
  }
  VisibilityWindowListener[] newVisibilityWindowListeners = new VisibilityWindowListener[visibilityWindowListeners.length - 1];
  System.arraycopy(visibilityWindowListeners, 0, newVisibilityWindowListeners, 0, index);
  System.arraycopy(visibilityWindowListeners, index + 1, newVisibilityWindowListeners, index, visibilityWindowListeners.length - index - 1);
  visibilityWindowListeners = newVisibilityWindowListeners;
}

/**
* Renders HTML.
*
* <p>
* The html parameter is Unicode encoded since it is a java <code>String</code>.
* As a result, the HTML meta tag charset should not be set. The charset is implied
* by the <code>String</code> itself.
*
* @param html the HTML content to be rendered
*
* @return true if the operation was successful and false otherwise.
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the html is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
* @see #setUrl
*
* @since 3.0
*/
public boolean setText(String html) {
  checkWidget();
  if (html == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  /*
  * Bug in Safari.  The web view segment faults in some circunstances
  * when the text changes during the location changing callback.  The
  * fix is to defer the work until the callback is done.
  */
  if (changingLocation) {
    this.html = html;
  } else {
    _setText(html);
  }
  return true;
}
 
void _setText(String html) { 
  int length = html.length();
  char[] buffer = new char[length];
  html.getChars(0, length, buffer, 0);
  int string = OS.CFStringCreateWithCharacters(0, buffer, length);

  String baseURL = "about:blank"; //$NON-NLS-1$
  length = baseURL.length();
  buffer = new char[length];
  baseURL.getChars(0, length, buffer, 0);
  int URLString = OS.CFStringCreateWithCharacters(0, buffer, length);
 
  /*
  * Note.  URLWithString uses autorelease.  The resulting URL
  * does not need to be released.
  * URL = [NSURL URLWithString:(NSString *)URLString]
  */ 
  int URL = WebKit.objc_msgSend(WebKit.C_NSURL, WebKit.S_URLWithString, URLString);
  OS.CFRelease(URLString);

  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
 
  //mainFrame = [webView mainFrame];
  int mainFrame = WebKit.objc_msgSend(webView, WebKit.S_mainFrame);
 
  //[mainFrame loadHTMLString:(NSString *) string baseURL:(NSURL *)URL];
  WebKit.objc_msgSend(mainFrame, WebKit.S_loadHTMLStringbaseURL, string, URL);
  OS.CFRelease(string);
}

/**
* Loads a URL.
*
* @param url the URL to be loaded
*
* @return true if the operation was successful and false otherwise.
*
* @exception IllegalArgumentException <ul>
*    <li>ERROR_NULL_ARGUMENT - if the url is null</li>
* </ul>
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
* @see #getUrl
*
* @since 3.0
*/
public boolean setUrl(String url) {
  checkWidget();
  if (url == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);

  html = null;

  StringBuffer buffer = new StringBuffer();
  if (url.indexOf('/') == 0) buffer.append("file://"); //$NON-NLS-1$  //$NON-NLS-2$
  else if (url.indexOf(':') == -1) buffer.append("http://");   //$NON-NLS-1$
  for (int i = 0; i < url.length(); i++) {
    char c = url.charAt(i);
    if (c == ' ') buffer.append("%20"); //$NON-NLS-1$  //$NON-NLS-2$
    else buffer.append(c);
  }
 
  int length = buffer.length();
  char[] chars = new char[length];
  buffer.getChars(0, length, chars, 0);
  int sHandle = OS.CFStringCreateWithCharacters(0, chars, length);

  /*
  * Note.  URLWithString uses autorelease.  The resulting URL
  * does not need to be released.
  * inURL = [NSURL URLWithString:(NSString *)sHandle]
  */ 
  int inURL= WebKit.objc_msgSend(WebKit.C_NSURL, WebKit.S_URLWithString, sHandle);
  OS.CFRelease(sHandle);
   
  //request = [NSURLRequest requestWithURL:(NSURL*)inURL];
  int request= WebKit.objc_msgSend(WebKit.C_NSURLRequest, WebKit.S_requestWithURL, inURL);
 
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
 
  //mainFrame = [webView mainFrame];
  int mainFrame= WebKit.objc_msgSend(webView, WebKit.S_mainFrame);

  //[mainFrame loadRequest:request];
  WebKit.objc_msgSend(mainFrame, WebKit.S_loadRequest, request);

  return true;
}

/**
* Stop any loading and rendering activity.
*
* @exception SWTException <ul>
*    <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
*    <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void stop() {
  checkWidget();
  html = null;
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  WebKit.objc_msgSend(webView, WebKit.S_stopLoading, 0);
}

/* WebFrameLoadDelegate */
 
void didFailProvisionalLoadWithError(int error, int frame) {
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) {
    /*
    * Feature on Safari.  The identifier is used here as a marker for the events
    * related to the top frame and the URL changes related to that top frame as
    * they should appear on the location bar of a browser.  It is expected to reset
    * the identifier to 0 when the event didFinishLoadingFromDataSource related to
    * the identifierForInitialRequest event is received.  Howeever, Safari fires
    * the didFinishLoadingFromDataSource event before the entire content of the
    * top frame is loaded.  It is possible to receive multiple willSendRequest
    * events in this interval, causing the Browser widget to send unwanted
    * Location.changing events.  For this reason, the identifier is reset to 0
    * when the top frame has either finished loading (didFinishLoadForFrame
    * event) or failed (didFailProvisionalLoadWithError).
    */
    identifier = 0;
  }
}

void didFinishLoadForFrame(int frame) {
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) {
    final Display display= getDisplay();
    final ProgressEvent progress = new ProgressEvent(this);
    progress.display = getDisplay();
    progress.widget = this;
    progress.current = MAX_PROGRESS;
    progress.total = MAX_PROGRESS;
    for (int i = 0; i < progressListeners.length; i++) {
      final ProgressListener listener = progressListeners[i];
      /*
      * Note on WebKit.  Running the event loop from a Browser
      * delegate callback breaks the WebKit (stop loading or
      * crash).  The widget ProgressBar currently touches the
      * event loop every time the method setSelection is called. 
      * The workaround is to invoke Display.asyncexec so that
      * the Browser does not crash when the user updates the
      * selection of the ProgressBar.
      */
      display.asyncExec(
        new Runnable() {
          public void run() {
            if (!display.isDisposed() && !isDisposed())
              listener.completed(progress);
          }
        }
      );
    }
    /*
    * Feature on Safari.  The identifier is used here as a marker for the events
    * related to the top frame and the URL changes related to that top frame as
    * they should appear on the location bar of a browser.  It is expected to reset
    * the identifier to 0 when the event didFinishLoadingFromDataSource related to
    * the identifierForInitialRequest event is received.  Howeever, Safari fires
    * the didFinishLoadingFromDataSource event before the entire content of the
    * top frame is loaded.  It is possible to receive multiple willSendRequest
    * events in this interval, causing the Browser widget to send unwanted
    * Location.changing events.  For this reason, the identifier is reset to 0
    * when the top frame has either finished loading (didFinishLoadForFrame
    * event) or failed (didFailProvisionalLoadWithError).
    */
    identifier = 0;
  }
}

void didReceiveTitle(int title, int frame) {
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) {
    int length = OS.CFStringGetLength(title);
    char[] buffer = new char[length];
    CFRange range = new CFRange();
    range.length = length;
    OS.CFStringGetCharacters(title, range, buffer);
    String newTitle = new String(buffer);
    TitleEvent newEvent = new TitleEvent(Browser.this);
    newEvent.display = getDisplay();
    newEvent.widget = this;
    newEvent.title = newTitle;
    for (int i = 0; i < titleListeners.length; i++)
      titleListeners[i].changed(newEvent);
  }
}

void didStartProvisionalLoadForFrame(int frame) {
  /*
  * This code is intentionally commented.  WebFrameLoadDelegate:didStartProvisionalLoadForFrame is
  * called before WebResourceLoadDelegate:willSendRequest and
  * WebFrameLoadDelegate:didCommitLoadForFrame.  The resource count is reset when didCommitLoadForFrame
  * is received for the top frame.
  */
//  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
//  if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) {
//    /* reset resource status variables */
//    resourceCount= 0;
//  }
}

void didCommitLoadForFrame(int frame) {
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  //id url= [[[[frame provisionalDataSource] request] URL] absoluteString];
  int dataSource = WebKit.objc_msgSend(frame, WebKit.S_dataSource);
  int request = WebKit.objc_msgSend(dataSource, WebKit.S_request);
  int url = WebKit.objc_msgSend(request, WebKit.S_URL);
  int s = WebKit.objc_msgSend(url, WebKit.S_absoluteString)
  int length = OS.CFStringGetLength(s);
  if (length == 0) return;
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(s, range, buffer);
  String url2 = new String(buffer);
  final Display display = getDisplay();

  boolean top = frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame);
  if (top) {
    /* reset resource status variables */
    resourceCount = 0;   
    this.url = url2;
   
    final ProgressEvent progress = new ProgressEvent(this);
    progress.display = display;
    progress.widget = this;
    progress.current = 1;
    progress.total = MAX_PROGRESS;
    for (int i = 0; i < progressListeners.length; i++) {
      final ProgressListener listener = progressListeners[i];
      /*
      * Note on WebKit.  Running the event loop from a Browser
      * delegate callback breaks the WebKit (stop loading or
      * crash).  The widget ProgressBar currently touches the
      * event loop every time the method setSelection is called. 
      * The workaround is to invoke Display.asyncexec so that
      * the Browser does not crash when the user updates the
      * selection of the ProgressBar.
      */
      display.asyncExec(
        new Runnable() {
          public void run() {
            if (!display.isDisposed() && !isDisposed())
              listener.changed(progress);
          }
        }
      );
    }
   
    StatusTextEvent statusText = new StatusTextEvent(this);
    statusText.display = display;
    statusText.widget = this;
    statusText.text = url2;
    for (int i = 0; i < statusTextListeners.length; i++)
      statusTextListeners[i].changed(statusText);
  }
  LocationEvent location = new LocationEvent(Browser.this);
  location.display = display;
  location.widget = this;
  location.location = url2;
  location.top = top;
  for (int i = 0; i < locationListeners.length; i++)
    locationListeners[i].changed(location);
}

/* WebResourceLoadDelegate */

void didFinishLoadingFromDataSource(int identifier, int dataSource) {
  /*
  * Feature on Safari.  The identifier is used here as a marker for the events
  * related to the top frame and the URL changes related to that top frame as
  * they should appear on the location bar of a browser.  It is expected to reset
  * the identifier to 0 when the event didFinishLoadingFromDataSource related to
  * the identifierForInitialRequest event is received.  Howeever, Safari fires
  * the didFinishLoadingFromDataSource event before the entire content of the
  * top frame is loaded.  It is possible to receive multiple willSendRequest
  * events in this interval, causing the Browser widget to send unwanted
  * Location.changing events.  For this reason, the identifier is reset to 0
  * when the top frame has either finished loading (didFinishLoadForFrame
  * event) or failed (didFailProvisionalLoadWithError).
  */
  // this code is intentionally commented
  //if (this.identifier == identifier) this.identifier = 0;
}

void didFailLoadingWithError(int identifier, int error, int dataSource) {
  /*
  * Feature on Safari.  The identifier is used here as a marker for the events
  * related to the top frame and the URL changes related to that top frame as
  * they should appear on the location bar of a browser.  It is expected to reset
  * the identifier to 0 when the event didFinishLoadingFromDataSource related to
  * the identifierForInitialRequest event is received.  Howeever, Safari fires
  * the didFinishLoadingFromDataSource event before the entire content of the
  * top frame is loaded.  It is possible to receive multiple willSendRequest
  * events in this interval, causing the Browser widget to send unwanted
  * Location.changing events.  For this reason, the identifier is reset to 0
  * when the top frame has either finished loading (didFinishLoadForFrame
  * event) or failed (didFailProvisionalLoadWithError).
  */
  // this code is intentionally commented
  //if (this.identifier == identifier) this.identifier = 0;
}

int identifierForInitialRequest(int request, int dataSource) {
  final Display display = getDisplay();
  final ProgressEvent progress = new ProgressEvent(this);
  progress.display = display;
  progress.widget = this;
  progress.current = resourceCount;
  progress.total = Math.max(resourceCount, MAX_PROGRESS);
  for (int i = 0; i < progressListeners.length; i++) {
    final ProgressListener listener = progressListeners[i];
    /*
    * Note on WebKit.  Running the event loop from a Browser
    * delegate callback breaks the WebKit (stop loading or
    * crash).  The widget ProgressBar currently touches the
    * event loop every time the method setSelection is called. 
    * The workaround is to invoke Display.asyncexec so that
    * the Browser does not crash when the user updates the
    * selection of the ProgressBar.
    */
    display.asyncExec(
      new Runnable() {
        public void run() {
          if (!display.isDisposed() && !isDisposed())
            listener.changed(progress);
        }
      }
    );
  }

  /*
  * Note.  numberWithInt uses autorelease.  The resulting object
  * does not need to be released.
  * identifier = [NSNumber numberWithInt: resourceCount++]
  */ 
  int identifier = WebKit.objc_msgSend(WebKit.C_NSNumber, WebKit.S_numberWithInt, resourceCount++);
   
  if (this.identifier == 0) {
    int webView = WebKit.HIWebViewGetWebView(webViewHandle);
    int frame = WebKit.objc_msgSend(dataSource, WebKit.S_webFrame);
    if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) this.identifier = identifier;
  }
  return identifier;
   
}

int willSendRequest(int identifier, int request, int redirectResponse, int dataSource) {
  return request;
}

/* handleNotification */

void handleNotification(int notification) { 
}

/* UIDelegate */
int createWebViewWithRequest(int request) {
  WindowEvent newEvent = new WindowEvent(Browser.this);
  newEvent.display = getDisplay();
  newEvent.widget = this;
  newEvent.required = true;
  if (openWindowListeners != null) {
    for (int i = 0; i < openWindowListeners.length; i++)
      openWindowListeners[i].open(newEvent);
  }
  int webView = 0;
  Browser browser = newEvent.browser;
  if (browser != null && !browser.isDisposed()) {
    webView = WebKit.HIWebViewGetWebView(browser.webViewHandle);
   
    if (request != 0) {
      //mainFrame = [webView mainFrame];
      int mainFrame= WebKit.objc_msgSend(webView, WebKit.S_mainFrame);

      //[mainFrame loadRequest:request];
      WebKit.objc_msgSend(mainFrame, WebKit.S_loadRequest, request);
    }
  }
  return webView;
}

void webViewShow(int sender) {
  /*
  * Feature on WebKit.  The Safari WebKit expects the application
  * to create a new Window using the Objective C Cocoa API in response
  * to UIDelegate.createWebViewWithRequest. The application is then
  * expected to use Objective C Cocoa API to make this window visible
  * when receiving the UIDelegate.webViewShow message.  For some reason,
  * a window created with the Carbon API hosting the new browser instance
  * does not redraw until it has been resized.  The fix is to increase the
  * size of the Shell and restore it to its initial size.
  */
  Shell parent = getShell();
  Point pt = parent.getSize();
  parent.setSize(pt.x+1, pt.y);
  parent.setSize(pt.x, pt.y);
  WindowEvent newEvent = new WindowEvent(this);
  newEvent.display = getDisplay();
  newEvent.widget = this;
  if (location != null) newEvent.location = location;
  if (size != null) newEvent.size = size;
  /*
  * Feature in Safari.  Safari's tool bar contains
  * the address bar.  The address bar is displayed
  * if the tool bar is displayed. There is no separate
  * notification for the address bar.
  * Feature in Safari.  The menu bar is always
  * displayed. There is no notification to hide
  * the menu bar.
  */
  newEvent.addressBar = toolBar;
  newEvent.menuBar = true;
  newEvent.statusBar = statusBar;
  newEvent.toolBar = toolBar;
  for (int i = 0; i < visibilityWindowListeners.length; i++)
    visibilityWindowListeners[i].show(newEvent);
  location = null;
  size = null;
}

void setFrame(int frame) {
  float[] dest = new float[4];
  OS.memcpy(dest, frame, 16);
  /* convert to SWT system coordinates */
  Rectangle bounds = getDisplay().getBounds();
  location = new Point((int)dest[0], bounds.height - (int)dest[1] - (int)dest[3]);
  size = new Point((int)dest[2], (int)dest[3]);
}

void webViewFocus() {
}

void webViewUnfocus() {
}

void runJavaScriptAlertPanelWithMessage(int message) {
  int length = OS.CFStringGetLength(message);
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(message, range, buffer);
  String text = new String(buffer);

  MessageBox messageBox = new MessageBox(getShell(), SWT.OK | SWT.ICON_WARNING);
  messageBox.setText("Javascript")//$NON-NLS-1$
  messageBox.setMessage(text);
  messageBox.open();
}

int runJavaScriptConfirmPanelWithMessage(int message) {
  int length = OS.CFStringGetLength(message);
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(message, range, buffer);
  String text = new String(buffer);

  MessageBox messageBox = new MessageBox(getShell(), SWT.OK | SWT.CANCEL | SWT.ICON_QUESTION);
  messageBox.setText("Javascript")//$NON-NLS-1$
  messageBox.setMessage(text);
  return messageBox.open() == SWT.OK ? 1 : 0;
}

void runOpenPanelForFileButtonWithResultListener(int resultListener) {
  FileDialog dialog = new FileDialog(getShell(), SWT.NONE);
  String result = dialog.open();
  if (result == null) {
    WebKit.objc_msgSend(resultListener, WebKit.S_cancel);
    return;
  }
  int length = result.length();
  char[] buffer = new char[length];
  result.getChars(0, length, buffer, 0);
  int filename = OS.CFStringCreateWithCharacters(0, buffer, length);
  WebKit.objc_msgSend(resultListener, WebKit.S_chooseFilename, filename);
  OS.CFRelease(filename);
}
void webViewClose() {
  Shell parent = getShell();
  WindowEvent newEvent = new WindowEvent(this);
  newEvent.display = getDisplay();
  newEvent.widget = this;
  for (int i = 0; i < closeWindowListeners.length; i++)
    closeWindowListeners[i].close(newEvent)
  dispose();
  if (parent.isDisposed()) return;
  /*
  * Feature on WebKit.  The Safari WebKit expects the application
  * to create a new Window using the Objective C Cocoa API in response
  * to UIDelegate.createWebViewWithRequest. The application is then
  * expected to use Objective C Cocoa API to make this window visible
  * when receiving the UIDelegate.webViewShow message.  For some reason,
  * a window created with the Carbon API hosting the new browser instance
  * does not redraw until it has been resized.  The fix is to increase the
  * size of the Shell and restore it to its initial size.
  */
  Point pt = parent.getSize();
  parent.setSize(pt.x+1, pt.y);
  parent.setSize(pt.x, pt.y);
}

int contextMenuItemsForElement(int element, int defaultMenuItems) {
  org.eclipse.swt.internal.carbon.Point pt = new org.eclipse.swt.internal.carbon.Point();
  OS.GetGlobalMouse(pt);
  Event event = new Event();
  event.x = pt.h;
  event.y = pt.v;
  notifyListeners(SWT.MenuDetect, event);
  Menu menu = getMenu();
  if (!event.doit) return 0;
  if (menu != null && !menu.isDisposed()) {
    if (event.x != pt.h || event.y != pt.v) {
      menu.setLocation(event.x, event.y);
    }
    menu.setVisible(true);
    return 0;
  }
  return defaultMenuItems;
}

void setStatusBarVisible(int visible) {
  /* Note.  Webkit only emits the notification when the status bar should be hidden. */
  statusBar = visible != 0;
}

void setStatusText(int text) {
  int length = OS.CFStringGetLength(text);
  if (length == 0) return;
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(text, range, buffer);

  StatusTextEvent statusText = new StatusTextEvent(this);
  statusText.display = getDisplay();
  statusText.widget = this;
  statusText.text = new String(buffer);
  for (int i = 0; i < statusTextListeners.length; i++)
    statusTextListeners[i].changed(statusText);
}

void setResizable(int visible) {
}

void setToolbarsVisible(int visible) {
  /* Note.  Webkit only emits the notification when the tool bar should be hidden. */
  toolBar = visible != 0;
}

/* PolicyDelegate */

void decidePolicyForMIMEType(int type, int request, int frame, int listener) {
  boolean canShow = WebKit.objc_msgSend(WebKit.C_WebView, WebKit.S_canShowMIMEType, type) != 0;
  WebKit.objc_msgSend(listener, canShow ? WebKit.S_use : WebKit.S_download);
}

void decidePolicyForNavigationAction(int actionInformation, int request, int frame, int listener) {
  int url = WebKit.objc_msgSend(request, WebKit.S_URL);
  if (url == 0) {
    /* indicates that a URL with an invalid format was specified */
    WebKit.objc_msgSend(listener, WebKit.S_ignore);
    return;
  }
  int s = WebKit.objc_msgSend(url, WebKit.S_absoluteString);
  int length = OS.CFStringGetLength(s);
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(s, range, buffer);
  String url2 = new String(buffer);

  LocationEvent newEvent = new LocationEvent(this);
  newEvent.display = getDisplay();
  newEvent.widget = this;
  newEvent.location = url2;
  newEvent.doit = true;
  if (locationListeners != null) {
    changingLocation = true;
    for (int i = 0; i < locationListeners.length; i++)
      locationListeners[i].changing(newEvent);
    changingLocation = false;
  }

  WebKit.objc_msgSend(listener, newEvent.doit ? WebKit.S_use : WebKit.S_ignore);

  if (html != null && !isDisposed()) {
    String html = this.html;
    this.html = null;
    _setText(html);
  }
}

void decidePolicyForNewWindowAction(int actionInformation, int request, int frameName, int listener) {
  WebKit.objc_msgSend(listener, WebKit.S_use);
}

void unableToImplementPolicyWithError(int error, int frame) {
}

/* WebDownload */

void decideDestinationWithSuggestedFilename (int download, int filename) {
  int length = OS.CFStringGetLength(filename);
  char[] buffer = new char[length];
  CFRange range = new CFRange();
  range.length = length;
  OS.CFStringGetCharacters(filename, range, buffer);
  String name = new String(buffer);
  FileDialog dialog = new FileDialog(getShell(), SWT.SAVE);
  dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$
  dialog.setFileName(name);
  String path = dialog.open();
  if (path == null) {
    /* cancel pressed */
    WebKit.objc_msgSend(download, WebKit.S_release);
    return;
  }
  length = path.length();
  char[] chars = new char[length];
  path.getChars(0, length, chars, 0);
  int result = OS.CFStringCreateWithCharacters(0, chars, length);
  WebKit.objc_msgSend(download, WebKit.S_setDestinationAllowOverwrite, result, 1);
  OS.CFRelease(result);
}

// GOOGLE: we need a notification when the window object is available so we can
// setup our own hooks before any JavaScript runs.
public interface WindowScriptObjectListener {
  public void windowScriptObjectAvailable(int windowScriptObject);
}

public void addWindowScriptObjectListener(WindowScriptObjectListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  WindowScriptObjectListener[] newWindowScriptObjectListeners = new WindowScriptObjectListener[windowScriptObjectListeners.length + 1];
  System.arraycopy(windowScriptObjectListeners, 0, newWindowScriptObjectListeners, 0, windowScriptObjectListeners.length);
  windowScriptObjectListeners = newWindowScriptObjectListeners;
  windowScriptObjectListeners[windowScriptObjectListeners.length - 1] = listener;
}

public void removeWindowScriptObjectListener(WindowScriptObjectListener listener) {
  checkWidget();
  if (listener == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
  if (windowScriptObjectListeners.length == 0) return;
  int index = -1;
  for (int i = 0; i < windowScriptObjectListeners.length; i++) {
    if (listener == windowScriptObjectListeners[i]) {
      index = i;
      break;
    }
  }
  if (index == -1) return;
  if (windowScriptObjectListeners.length == 1) {
    windowScriptObjectListeners = new WindowScriptObjectListener[0];
    return;
  }
  WindowScriptObjectListener[] newWindowScriptObjectListeners = new WindowScriptObjectListener[windowScriptObjectListeners.length - 1];
  System.arraycopy(windowScriptObjectListeners, 0, newWindowScriptObjectListeners, 0, index);
  System.arraycopy(windowScriptObjectListeners, index + 1, newWindowScriptObjectListeners, index, windowScriptObjectListeners.length - index - 1);
  windowScriptObjectListeners = newWindowScriptObjectListeners;
}

void fireWindowScriptObjectListeners(int windowScriptObject) {
  for (int i = 0; i < windowScriptObjectListeners.length; i++) {
    windowScriptObjectListeners[i].windowScriptObjectAvailable(windowScriptObject);
  }
}

public static void setWebInspectorEnabled(boolean isEnabled) {
  char[] name = "WebKitDeveloperExtras".toCharArray();
  int clsId = WebKit.objc_getClass("NSUserDefaults");
  if (clsId == 0) return;
  int sel_sud = WebKit.sel_registerName("standardUserDefaults");
  if (sel_sud == 0) return;
  int objId = WebKit.objc_msgSend(clsId, sel_sud);
  if (objId == 0) return;
  int sel_sbfk = WebKit.sel_registerName("setBool:forKey:");
  if (sel_sbfk == 0) return;
  int cfName = OS.CFStringCreateWithCharacters(0,name,name.length);
  if (cfName == 0) return;
  try {
    WebKit.objc_msgSend(objId, sel_sbfk, isEnabled ? 1 : 0, cfName);
  } finally {
    OS.CFRelease(cfName);
  }
}

public void setUserAgentApplicationName(String userAgent) {
  char[] chars = userAgent.toCharArray();
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  if (webView == 0) return;
  int sel = WebKit.sel_registerName("setApplicationNameForUserAgent:");
  if (sel == 0) return;
  int userAgentStr = OS.CFStringCreateWithCharacters(0, chars, chars.length);
  if (userAgentStr == 0) return;
  try {
    WebKit.objc_msgSend(webView, sel, userAgentStr);
  } finally {
    OS.CFRelease(userAgentStr);
  }
}

public void setNeedsDisplay(boolean value) {
  int webView = WebKit.HIWebViewGetWebView(webViewHandle);
  if (webView == 0) return;
  int sel = WebKit.sel_registerName("setNeedsDisplay:");
  if (sel == 0) return;
  WebKit.objc_msgSend(webView, sel, (value)?1:0);
}

WindowScriptObjectListener[] windowScriptObjectListeners = new WindowScriptObjectListener[0];
// end GOOGLE
}
TOP

Related Classes of org.eclipse.swt.browser.Browser$WindowScriptObjectListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.