/*******************************************************************************
* Copyright (c) 2003, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Chris McKillop (QNX Software Systems) - initial implementation
*******************************************************************************/
package org.eclipse.swt.browser;
import java.io.File;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.photon.*;
import org.eclipse.swt.widgets.*;
class Voyager extends WebBrowser {
int webHandle;
String url = ""; //$NON-NLS-1$
String text = ""; //$NON-NLS-1$
int textOffset;
int currentProgress;
int totalProgress = 25;
/* browser to redirect content to */
Browser redirectBrowser;
static int instanceCount = 0;
/* Package Name */
static Callback callback;
public void create(Composite parent, int style) {
/* use Photon's built-in anchoring for resizing */
int[] args = {
OS.Pt_ARG_ANCHOR_FLAGS,
OS.Pt_TOP_ANCHORED_TOP | OS.Pt_BOTTOM_ANCHORED_BOTTOM | OS.Pt_LEFT_ANCHORED_LEFT | OS.Pt_RIGHT_ANCHORED_RIGHT,
OS.Pt_TOP_ANCHORED_TOP | OS.Pt_BOTTOM_ANCHORED_BOTTOM | OS.Pt_LEFT_ANCHORED_LEFT | OS.Pt_RIGHT_ANCHORED_RIGHT,
OS.Pt_ARG_FILL_COLOR,
0xFFFFFF,
0 };
webHandle = OS.PtCreateWidget(OS.PtWebClient(), browser.handle, args.length / 3, args);
if (webHandle == 0) {
browser.dispose();
SWT.error (SWT.ERROR_NO_HANDLES);
}
/* configure the widget with a specific server */
File netfront = new File("/usr/photon/bin/netfront"); //$NON-NLS-1$
String name, server;
if (netfront.exists() || (OS.QNX_MAJOR >= 6 && OS.QNX_MINOR >= 3 && OS.QNX_MICRO >= 0)) {
name = "NetfrontServer"; //$NON-NLS-1$
server = "netfront"; //$NON-NLS-1$
} else {
name = "VoyagerServer-2"; //$NON-NLS-1$
server = "vserver"; //$NON-NLS-1$
}
/* set client name */
byte[] nameBuffer = Converter.wcsToMbcs(null, name, true);
int namePtr = OS.malloc(nameBuffer.length);
OS.memmove(namePtr, nameBuffer, nameBuffer.length);
OS.PtSetResource(webHandle, OS.Pt_ARG_CLIENT_NAME, namePtr, 0);
OS.free(namePtr);
/**
* Feature in Photon PtWebClient. If you give a server name
* when the widget is created it will attempt to start a new server
* rather then attaching a new window context to the existing server.
* If you don't connect to the existing one then javascript window
* creation will fail.
*/
if (instanceCount == 0) {
/* select server */
byte[] serverBuffer = Converter.wcsToMbcs(null, server, true);
int serverPtr = OS.malloc(serverBuffer.length);
OS.memmove(serverPtr, serverBuffer, serverBuffer.length);
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_SERVER, serverPtr, 0);
OS.free(serverPtr);
}
instanceCount++;
if (callback == null) callback = new Callback(this.getClass(), "webProc", 3, false); //$NON-NLS-1$
int webProc = callback.getAddress();
if (webProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_CLOSE_WINDOW, webProc, OS.Pt_CB_WEB_CLOSE_WINDOW);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_COMPLETE, webProc, OS.Pt_CB_WEB_COMPLETE);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_DATA_REQ, webProc, OS.Pt_CB_WEB_DATA_REQ);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_METADATA, webProc, OS.Pt_CB_WEB_METADATA);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_NEW_WINDOW, webProc, OS.Pt_CB_WEB_NEW_WINDOW);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_START, webProc, OS.Pt_CB_WEB_START);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_STATUS, webProc, OS.Pt_CB_WEB_STATUS);
OS.PtAddCallback(webHandle,OS.Pt_CB_WEB_URL, webProc, OS.Pt_CB_WEB_URL);
Listener listener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose: onDispose(); break;
case SWT.FocusIn: onFocusGained(event); break;
}
}
};
int[] folderEvents = new int[]{
SWT.Dispose,
SWT.FocusIn,
};
for (int i = 0; i < folderEvents.length; i++) {
browser.addListener(folderEvents[i], listener);
}
OS.PtRealizeWidget(webHandle);
}
static int webProc(int handle, int data, int info) {
Display display = Display.getCurrent();
int parent = OS.PtWidgetParent (handle);
Widget widget = display.findWidget(parent);
if (widget != null && widget instanceof Browser) {
Browser browser = (Browser)widget;
return ((Voyager)browser.webBrowser).webProc(data, info);
}
return OS.Pt_CONTINUE;
}
public boolean back() {
int ptr = OS.malloc(4);
int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
OS.PtGetResources(webHandle, args.length / 3, args);
int[] result = new int[1];
OS.memmove(result, ptr, 4);
OS.memmove(result, result[0], 4);
OS.free(ptr);
if ((result[0] & (1 << OS.Pt_WEB_DIRECTION_BACK)) == 0) return false;
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_NAVIGATE_PAGE, OS.Pt_WEB_DIRECTION_BACK, 0);
return true;
}
int webProc(int data, int info) {
switch (data) {
case OS.Pt_CB_WEB_CLOSE_WINDOW: return Pt_CB_WEB_CLOSE_WINDOW(info);
case OS.Pt_CB_WEB_COMPLETE: return Pt_CB_WEB_COMPLETE(info);
case OS.Pt_CB_WEB_DATA_REQ: return Pt_CB_WEB_DATA_REQ(info);
case OS.Pt_CB_WEB_METADATA: return Pt_CB_WEB_METADATA(info);
case OS.Pt_CB_WEB_NEW_WINDOW: return Pt_CB_WEB_NEW_WINDOW(info);
case OS.Pt_CB_WEB_START: return Pt_CB_WEB_START(info);
case OS.Pt_CB_WEB_STATUS: return Pt_CB_WEB_STATUS(info);
case OS.Pt_CB_WEB_URL: return Pt_CB_WEB_URL(info);
}
return OS.Pt_CONTINUE;
}
public boolean execute(String script) {
return false;
}
public boolean forward() {
int ptr = OS.malloc(4);
int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
OS.PtGetResources(webHandle, args.length / 3, args);
int[] result = new int[1];
OS.memmove(result, ptr, 4);
OS.memmove(result, result[0], 4);
OS.free(ptr);
if ((result[0] & (1 << OS.Pt_WEB_DIRECTION_FWD)) == 0) return false;
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_NAVIGATE_PAGE, OS.Pt_WEB_DIRECTION_FWD, 0);
return true;
}
public String getBrowserType () {
return "voyager"; //$NON-NLS-1$
}
public String getText () {
// TODO
return ""; //$NON-NLS-1$
}
public String getUrl() {
return url;
}
public boolean isBackEnabled() {
int ptr = OS.malloc(4);
int[] args = new int[] {OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
OS.PtGetResources(webHandle, args.length / 3, args);
int[] result = new int[1];
OS.memmove(result, ptr, 4);
OS.memmove(result, result[0], 4);
OS.free(ptr);
return (result[0] & (1 << OS.Pt_WEB_DIRECTION_BACK)) != 0;
}
public boolean isForwardEnabled() {
int ptr = OS.malloc(4);
int[] args = new int[]{OS.Pt_ARG_WEB_NAVIGATE_PAGE, ptr, 0};
OS.PtGetResources(webHandle, args.length / 3, args);
int[] result = new int[1];
OS.memmove(result, ptr, 4);
OS.memmove(result, result[0], 4);
OS.free(ptr);
return (result[0] & (1 << OS.Pt_WEB_DIRECTION_FWD)) != 0;
}
void onDispose() {
OS.PtDestroyWidget(webHandle);
webHandle = 0;
instanceCount--;
}
void onFocusGained(Event e) {
OS.PtContainerGiveFocus(webHandle, null);
}
int Pt_CB_WEB_CLOSE_WINDOW(int info) {
WindowEvent event = new WindowEvent(browser);
event.display = browser.getDisplay();
event.widget = browser;
for(int i = 0; i < closeWindowListeners.length; i++ )
closeWindowListeners[i].close(event);
browser.dispose();
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_COMPLETE(int info) {
Display display = browser.getDisplay();
LocationEvent event = new LocationEvent(browser);
event.display = display;
event.widget = browser;
event.location = url;
event.top = true;
for (int i = 0; i < locationListeners.length; i++)
locationListeners[i].changed(event);
ProgressEvent progress = new ProgressEvent(browser);
progress.display = display;
progress.widget = browser;
progress.current = totalProgress;
progress.total = totalProgress;
for (int i = 0; i < progressListeners.length; i++)
progressListeners[i].completed(progress);
StatusTextEvent statusevent = new StatusTextEvent(browser);
statusevent.display = display;
statusevent.widget = browser;
statusevent.text = ""; //$NON-NLS-1$
for (int i = 0; i < statusTextListeners.length; i++)
statusTextListeners[i].changed(statusevent);
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_DATA_REQ(int info) {
PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
PtWebDataReqCallback_t dataReq = new PtWebDataReqCallback_t();
OS.memmove(dataReq, cbinfo_t.cbdata, PtWebDataReqCallback_t.sizeof);
PtWebClient2Data_t clientData = new PtWebClient2Data_t();
clientData.type = dataReq.type;
clientData.data = 0;
String data = null;
switch (clientData.type) {
case OS.Pt_WEB_DATA_HEADER:
StringBuffer sb = new StringBuffer("Content-Type: text/html\n"); //$NON-NLS-1$
sb.append("Content-Length: "); //$NON-NLS-1$
sb.append(text.length());
sb.append("\n"); //$NON-NLS-1$
data = sb.toString();
break;
case OS.Pt_WEB_DATA_BODY:
/*
* Feature on Photon. The PtSetResource() call for PtWebClient data imposes
* a limit on the size of the text buffer being passed. The workaround is
* to break the text into 1KB chunks.
*/
if (text.length() - textOffset > 1024) {
data = text.substring(textOffset, textOffset + 1024);
textOffset += 1024;
} else {
data = text.substring(textOffset);
}
break;
case OS.Pt_WEB_DATA_CLOSE:
text = ""; //$NON-NLS-1$
break;
}
if (data != null) {
byte[] buffer = Converter.wcsToMbcs(null, data, true);
clientData.data = OS.malloc(buffer.length);
OS.memmove(clientData.data, buffer, buffer.length);
clientData.length = buffer.length - 1;
}
dataReq.url = clientData.url;
int ptr = OS.malloc(PtWebClient2Data_t.sizeof);
OS.memmove(ptr, clientData, PtWebClient2Data_t.sizeof);
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_DATA, clientData.data, ptr);
OS.free(ptr);
if (clientData.data != 0) OS.free(clientData.data);
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_METADATA(int info) {
PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
final PtWebMetaDataCallback_t webmeta_t = new PtWebMetaDataCallback_t();
OS.memmove(webmeta_t, cbinfo_t.cbdata, PtWebMetaDataCallback_t.sizeof);
String name = new String(webmeta_t.name, 0, OS.strlen(cbinfo_t.cbdata));
if (name.equals("title")) { //$NON-NLS-1$
String title = new String(webmeta_t.value, 0, OS.strlen(cbinfo_t.cbdata + webmeta_t.name.length));
TitleEvent newEvent = new TitleEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
newEvent.title = title;
/*
* Feature on Photon. The Voyager Browser updates the title section
* in the window decoration even if the title refers to an inner frame.
* Browsers on other platforms only update the title that refers to
* the top frame. As a result, the title event on Photon is sent for
* both top and inner frames.
*/
for (int i = 0; i < titleListeners.length; i++)
titleListeners[i].changed(newEvent);
}
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_NEW_WINDOW(int info) {
PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
final PtWebWindowCallback_t webwin_t = new PtWebWindowCallback_t();
OS.memmove(webwin_t,cbinfo_t.cbdata,PtWebWindowCallback_t.sizeof);
/*
* Feature on Photon. The server will use the first PtWebClient
* widget created from within the CB_WEB_NEW_WINDOW callback to
* host the new window. The workaround is to create a temporary
* PtWebClient widget everytime the notification is received.
* When its location is known, the Browser provided by the
* application is then redirected.
*/
final Browser hidden = new Browser(browser.getParent(), SWT.NONE);
hidden.addLocationListener(new LocationListener() {
public void changed(org.eclipse.swt.browser.LocationEvent event) {
/*
* Bug on Voyager. The first PtWebClient widget created
* from within the CB_WEB_NEW_WINDOW callback is the one
* hosting the new window. For some reason, this PtWebClient
* widget may or may not receive a Pt_CB_WEB_URL
* notification. It receives a Pt_CB_WEB_COMPLETE in all cases.
* The workaround is to reload the content when this occurs.
* This request causes the Pt_CB_WEB_URL to be correctly sent,
* providing the information required to redirect the browser
* provided by the application.
*/
if (event.location.length() == 0) {
hidden.refresh();
return;
}
hidden.dispose();
}
public void changing(final org.eclipse.swt.browser.LocationEvent event) {
Browser redirect = ((Voyager)hidden.webBrowser).redirectBrowser;
/* Forward the link to the Browser actually provided by the user */
if (redirect != null && !redirect.isDisposed()) {
WindowEvent newEvent = new WindowEvent(redirect);
newEvent.display = browser.getDisplay();
newEvent.widget = redirect;
newEvent.location = null;
/* Photon sets the size to 0,0 when it isn't specified. */
newEvent.size = webwin_t.size_w == 0 && webwin_t.size_h == 0 ? null : new Point(webwin_t.size_w, webwin_t.size_h);
for (int i = 0; i < redirect.webBrowser.visibilityWindowListeners.length; i++)
redirect.webBrowser.visibilityWindowListeners[i].show(newEvent);
redirect.setUrl(event.location);
}
}
});
WindowEvent event = new WindowEvent(browser);
event.display = browser.getDisplay();
event.widget = browser;
event.required = true;
for (int i = 0; i < openWindowListeners.length; i++)
openWindowListeners[i].open(event);
if (event.browser != null && !event.browser.isDisposed()) ((Voyager)hidden.webBrowser).redirectBrowser = event.browser;
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_START(int info) {
currentProgress = 1;
ProgressEvent progress = new ProgressEvent(browser);
progress.display = browser.getDisplay();
progress.widget = browser;
progress.current = currentProgress;
progress.total = totalProgress;
for (int i = 0; i < progressListeners.length; i++)
progressListeners[i].changed(progress);
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_STATUS(int info) {
PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
PtWebStatusCallback_t webstatus = new PtWebStatusCallback_t();
OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
OS.memmove(webstatus, cbinfo_t.cbdata, PtWebStatusCallback_t.sizeof);
switch (webstatus.type) {
case OS.Pt_WEB_STATUS_MOUSE :
case OS.Pt_WEB_STATUS_PROGRESS :
StatusTextEvent statusevent = new StatusTextEvent(browser);
statusevent.display = browser.getDisplay();
statusevent.widget = browser;
statusevent.text = new String(webstatus.desc, 0, OS.strlen(cbinfo_t.cbdata));
for (int i = 0; i < statusTextListeners.length; i++)
statusTextListeners[i].changed(statusevent);
if (webstatus.type == OS.Pt_WEB_STATUS_PROGRESS) {
currentProgress++;
if (currentProgress >= totalProgress) currentProgress = 1;
ProgressEvent progress = new ProgressEvent(browser);
progress.display = browser.getDisplay();
progress.widget = browser;
progress.current = currentProgress;
progress.total = totalProgress;
for (int i = 0; i < progressListeners.length; i++)
progressListeners[i].changed(progress);
}
break;
}
return OS.Pt_CONTINUE;
}
int Pt_CB_WEB_URL(int info) {
PtCallbackInfo_t cbinfo_t = new PtCallbackInfo_t();
OS.memmove(cbinfo_t, info, PtCallbackInfo_t.sizeof);
byte[] buffer = new byte[OS.strlen(cbinfo_t.cbdata) + 1];
OS.memmove(buffer, cbinfo_t.cbdata, buffer.length);
url = new String(Converter.mbcsToWcs(null, buffer));
LocationEvent event = new LocationEvent(browser);
event.display = browser.getDisplay();
event.widget = browser;
event.location = url;
event.doit = true;
for (int i = 0; i < locationListeners.length; i++)
locationListeners[i].changing(event);
/* Widget could have been disposed */
if (browser.isDisposed()) return OS.Pt_CONTINUE;
if (!event.doit) stop();
return OS.Pt_CONTINUE;
}
public void refresh() {
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_RELOAD, 1, 0);
}
public boolean setText(String html, boolean trusted) {
text = html;
textOffset = 0;
byte[] buffer = Converter.wcsToMbcs(null, "client:", true); //$NON-NLS-1$
int ptr = OS.malloc(buffer.length);
OS.memmove(ptr, buffer, buffer.length);
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_GET_URL, ptr, OS.Pt_WEB_ACTION_DISPLAY);
OS.free(ptr);
return true;
}
public boolean setUrl(String url, String postData, String[] headers) {
byte[] buffer = Converter.wcsToMbcs(null, url, true);
int ptr = OS.malloc(buffer.length);
OS.memmove(ptr, buffer, buffer.length);
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_GET_URL, ptr, OS.Pt_WEB_ACTION_DISPLAY);
OS.free(ptr);
return true;
}
public void stop() {
OS.PtSetResource(webHandle, OS.Pt_ARG_WEB_STOP, 1, 0);
}
}