001: /*
002: * Copyright 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell.mac;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.dev.shell.BrowserWidget;
020: import com.google.gwt.dev.shell.BrowserWidgetHost;
021: import com.google.gwt.dev.shell.ModuleSpace;
022: import com.google.gwt.dev.shell.ModuleSpaceHost;
023: import com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchMethod;
024: import com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchObject;
025:
026: import org.eclipse.swt.browser.Browser;
027: import org.eclipse.swt.browser.WebKit;
028: import org.eclipse.swt.widgets.Shell;
029:
030: /**
031: * Represents an individual browser window and all of its controls.
032: */
033: public class BrowserWidgetSaf extends BrowserWidget {
034: private class ExternalObject implements DispatchObject {
035:
036: public int getField(String name) {
037: if ("gwtonload".equalsIgnoreCase(name)) {
038: return LowLevelSaf.wrapFunction("gwtOnload",
039: new GwtOnLoad());
040: }
041: return 0;
042: }
043:
044: public Object getTarget() {
045: return null;
046: }
047:
048: public boolean gwtOnLoad(int scriptObject, String moduleName) {
049: try {
050: if (moduleName == null) {
051: // Indicates one or more modules are being unloaded.
052: handleUnload(scriptObject);
053: return true;
054: }
055:
056: // Attach a new ModuleSpace to make it programmable.
057: //
058: Integer key = new Integer(scriptObject);
059: ModuleSpaceHost msh = getHost().createModuleSpaceHost(
060: BrowserWidgetSaf.this , moduleName);
061: ModuleSpace moduleSpace = new ModuleSpaceSaf(msh,
062: scriptObject, moduleName, key);
063: attachModuleSpace(moduleSpace);
064: return true;
065: } catch (Throwable e) {
066: // We do catch Throwable intentionally because there are a ton of things
067: // that can go wrong trying to load a module, including Error-dervied
068: // things like NoClassDefFoundError.
069: //
070: getHost().getLogger().log(TreeLogger.ERROR,
071: "Failure to load module '" + moduleName + "'",
072: e);
073: return false;
074: }
075: }
076:
077: public void setField(String name, int value) {
078: }
079:
080: /**
081: * Unload one or more modules.
082: *
083: * @param scriptObject window to unload, 0 if all
084: */
085: protected void handleUnload(int scriptObject) {
086: Integer key = null;
087: if (scriptObject != 0) {
088: key = new Integer(scriptObject);
089: }
090: doUnload(key);
091: }
092: }
093:
094: private static final class GwtOnLoad implements DispatchMethod {
095:
096: public int invoke(int execState, int jsthis , int[] jsargs) {
097: int jsFalse = LowLevelSaf.convertBoolean(false);
098: LowLevelSaf.pushExecState(execState);
099: try {
100: if (!LowLevelSaf.isWrappedDispatch(jsthis )) {
101: return jsFalse;
102: }
103:
104: Object this Obj = LowLevelSaf.unwrapDispatch(jsthis );
105: if (!(this Obj instanceof ExternalObject)) {
106: return jsFalse;
107: }
108:
109: if (jsargs.length < 2) {
110: return jsFalse;
111: }
112:
113: if (!LowLevelSaf.isObject(jsargs[0])) {
114: return jsFalse;
115: }
116: if (!LowLevelSaf.isNull(jsargs[1])
117: && !LowLevelSaf.isString(jsargs[1])) {
118: return jsFalse;
119: }
120: String moduleName = LowLevelSaf.coerceToString(
121: execState, jsargs[1]);
122:
123: boolean result = ((ExternalObject) this Obj).gwtOnLoad(
124: jsargs[0], moduleName);
125: return LowLevelSaf.convertBoolean(result);
126: } catch (Throwable e) {
127: return jsFalse;
128: } finally {
129: LowLevelSaf.popExecState(execState);
130: }
131: }
132: }
133:
134: private static final int REDRAW_PERIOD = 250;
135:
136: static {
137: LowLevelSaf.init();
138: }
139:
140: public BrowserWidgetSaf(Shell shell, BrowserWidgetHost host) {
141: super (shell, host);
142:
143: Browser.setWebInspectorEnabled(true);
144: browser.setUserAgentApplicationName("Safari 419.3");
145: browser
146: .addWindowScriptObjectListener(new Browser.WindowScriptObjectListener() {
147:
148: public void windowScriptObjectAvailable(
149: int windowScriptObject) {
150: int sel = WebKit.sel_registerName("_imp");
151: int windowObject = WebKit.objc_msgSend(
152: windowScriptObject, sel);
153: try {
154: LowLevelSaf.jsLock();
155: final int globalExec = LowLevelSaf
156: .getGlobalExecState(windowObject);
157: int external = LowLevelSaf
158: .wrapDispatch(new ExternalObject());
159: LowLevelSaf.executeScript(globalExec,
160: "function __defineExternal(x) {"
161: + " window.external = x;"
162: + "}");
163: LowLevelSaf.invoke(globalExec,
164: windowObject, "__defineExternal",
165: windowObject,
166: new int[] { external });
167: } finally {
168: LowLevelSaf.jsUnlock();
169: }
170: }
171:
172: });
173:
174: /*
175: * HACK (knorton) - SWT wrapper on WebKit seems to cause unreliable repaints
176: * when the DOM changes inside of WebView. To compensate for this, every
177: * quarter second, we tell WebView to repaint itself fully.
178: */
179: getDisplay().timerExec(REDRAW_PERIOD, new Runnable() {
180: public void run() {
181: if (browser.isDisposed() || isDisposed()) {
182: // stop running if we're disposed
183: return;
184: }
185: // Force the browser to refresh
186: browser.setNeedsDisplay(true);
187: // Reschedule this object to run again
188: getDisplay().timerExec(REDRAW_PERIOD, this );
189: }
190: });
191: }
192:
193: @Override
194: public String getUserAgent() {
195: // See UserAgent.gwt.xml
196: return "safari";
197: }
198: }
|