Package com.google.gwt.dev.shell.mac

Source Code of com.google.gwt.dev.shell.mac.BrowserWidgetSaf

/*
* Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.shell.mac;

import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.dev.shell.BrowserWidget;
import com.google.gwt.dev.shell.BrowserWidgetHost;
import com.google.gwt.dev.shell.ModuleSpace;
import com.google.gwt.dev.shell.ModuleSpaceHost;
import com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchMethod;
import com.google.gwt.dev.shell.mac.LowLevelSaf.DispatchObject;

import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.widgets.Shell;

import java.util.HashMap;
import java.util.Map;

/**
* Represents an individual browser window and all of its controls.
*/
public class BrowserWidgetSaf extends BrowserWidget {
  private class ExternalObject implements DispatchObject {

    public int getField(int jsContext, String name) {
      if ("gwtonload".equalsIgnoreCase(name)) {
        return LowLevelSaf.wrapDispatchMethod(jsContext, "gwtOnload",
            new GwtOnLoad());
      } else if ("initmodule".equalsIgnoreCase(name)) {
        return LowLevelSaf.wrapDispatchMethod(jsContext, "initModule",
            new InitModule());
      }
      // Native code eats the same ref it gave us.
      return LowLevelSaf.getJsUndefined(jsContext);
    }

    public Object getTarget() {
      return this;
    }

    public boolean gwtOnLoad(int scriptObject, String moduleName, String version) {
      if (moduleName == null) {
        // Indicates one or more modules are being unloaded.
        return handleUnload(scriptObject);
      }

      TreeLogger logger = getHost().getLogger().branch(TreeLogger.DEBUG,
          "Loading an instance of module '" + moduleName + "'");
      try {
        if (!validHostedHtmlVersion(version)) {
          return false;
        }

        // Attach a new ModuleSpace to make it programmable.
        //
        Integer key = new Integer(scriptObject);
        ModuleSpaceHost msh = getHost().createModuleSpaceHost(logger,
            BrowserWidgetSaf.this, moduleName);

        /*
         * The global context for each window object is recorded during the
         * windowScriptObjectAvailable event. Now that we know which window
         * belongs to this module, we can resolve the correct global context.
         */
        final int globalContext = globalContexts.get(scriptObject).intValue();

        ModuleSpace moduleSpace = new ModuleSpaceSaf(logger, msh, scriptObject,
            globalContext, moduleName, key);
        attachModuleSpace(logger, moduleSpace);
        return true;
      } catch (Throwable e) {
        // We do catch Throwable intentionally because there are a ton of things
        // that can go wrong trying to load a module, including Error-dervied
        // things like NoClassDefFoundError.
        //
        logger.log(TreeLogger.ERROR, "Failure to load module '" + moduleName
            + "'", e);
        return false;
      }
    }

    /**
     * Causes a link to occur for the specified module.
     *
     * @param moduleName the module name to link
     * @return <code>true</code> if this module is stale and should be
     *         reloaded
     */
    public boolean initModule(String moduleName) {
      return getHost().initModule(moduleName);
    }

    public void setField(int jsContext, String name, int value) {
      try {
        // TODO (knorton): This should produce an error. The SetProperty
        // callback on the native side should be changed to pass an exception
        // array.
      } finally {
        LowLevelSaf.gcUnprotect(jsContext, value);
      }
    }

    /**
     * Unload one or more modules.
     *
     * @param scriptObject window to unload, 0 if all
     */
    protected boolean handleUnload(int scriptObject) {
      try {
        Integer key = null;
        if (scriptObject != 0) {
          key = new Integer(scriptObject);
        }
        doUnload(key);
        return true;
      } catch (Throwable e) {
        getHost().getLogger().log(TreeLogger.ERROR,
            "Failure to unload modules", e);
        return false;
      }
    }
  }

  private final class GwtOnLoad implements DispatchMethod {

    public int invoke(int jsContext, int jsthis, int[] jsargs, int[] exception) {
      int jsFalse = LowLevelSaf.toJsBoolean(jsContext, false);
      LowLevelSaf.pushJsContext(jsContext);
      try {
        if (!LowLevelSaf.isDispatchObject(jsContext, jsthis)) {
          return jsFalse;
        }

        Object thisObj = LowLevelSaf.unwrapDispatchObject(jsContext, jsthis);
        if (!(thisObj instanceof ExternalObject)) {
          return jsFalse;
        }

        if (jsargs.length < 3) {
          reportIncorrectInvocation("gwtOnLoad", 3, jsargs.length);
          return jsFalse;
        }

        if (!LowLevelSaf.isJsObject(jsContext, jsargs[0])) {
          return jsFalse;
        }
        if (!LowLevelSaf.isJsNull(jsContext, jsargs[1])
            && !LowLevelSaf.isJsString(jsContext, jsargs[1])) {
          return jsFalse;
        }
        String moduleName = LowLevelSaf.toString(jsContext, jsargs[1]);

        if (!LowLevelSaf.isJsString(jsContext, jsargs[2])) {
          return jsFalse;
        }
        String version = LowLevelSaf.toString(jsContext, jsargs[2]);

        boolean result = ((ExternalObject) thisObj).gwtOnLoad(jsargs[0],
            moduleName, version);
        // Native code eats the same ref it gave us.
        return LowLevelSaf.toJsBoolean(jsContext, result);
      } catch (Throwable e) {
        return jsFalse;
      } finally {
        for (int jsarg : jsargs) {
          LowLevelSaf.gcUnprotect(jsContext, jsarg);
        }
        LowLevelSaf.gcUnprotect(jsContext, jsthis);
        LowLevelSaf.popJsContext(jsContext);
      }
    }
  }

  private final class InitModule implements DispatchMethod {

    public int invoke(int jsContext, int jsthis, int[] jsargs, int[] exception) {
      int jsFalse = LowLevelSaf.toJsBoolean(jsContext, false);
      LowLevelSaf.pushJsContext(jsContext);
      try {
        if (!LowLevelSaf.isDispatchObject(jsContext, jsthis)) {
          return jsFalse;
        }

        Object thisObj = LowLevelSaf.unwrapDispatchObject(jsContext, jsthis);
        if (!(thisObj instanceof ExternalObject)) {
          return jsFalse;
        }

        if (jsargs.length < 1) {
          reportIncorrectInvocation("initModule", 1, jsargs.length);
          return jsFalse;
        }

        if (!LowLevelSaf.isJsString(jsContext, jsargs[0])) {
          return jsFalse;
        }
        String moduleName = LowLevelSaf.toString(jsContext, jsargs[0]);

        boolean result = ((ExternalObject) thisObj).initModule(moduleName);
        // Native code eats the same ref it gave us.
        return LowLevelSaf.toJsBoolean(jsContext, result);
      } catch (Throwable e) {
        return jsFalse;
      } finally {
        for (int jsarg : jsargs) {
          LowLevelSaf.gcUnprotect(jsContext, jsarg);
        }
        LowLevelSaf.gcUnprotect(jsContext, jsthis);
        LowLevelSaf.popJsContext(jsContext);
      }
    }
  }

  private static final int REDRAW_PERIOD = 250;

  static {
    LowLevelSaf.init();
  }

  private final Map<Integer, Integer> globalContexts = new HashMap<Integer, Integer>();

  public BrowserWidgetSaf(Shell shell, BrowserWidgetHost host) {
    super(shell, host);

    Browser.setWebInspectorEnabled(true);
    browser.addWindowScriptObjectListener(new Browser.WindowScriptObjectListener() {

      public void windowScriptObjectAvailable(int windowScriptObject) {
        /*
         * When GwtOnLoad fires we may not be able to get to the JSGlobalContext
         * that corresponds to our module frame (since the call to GwtOnLoad
         * could originate in the main page. So as each frame fires a
         * windowScriptObjectAvailable event, we must store all window,
         * globalContext pairs in a HashMap so we can later look up the global
         * context by window object when GwtOnLoad is called.
         */
        int jsGlobalContext = browser.getGlobalContextForWindowObject(windowScriptObject);
        int jsGlobalObject = LowLevelSaf.getGlobalJsObject(jsGlobalContext);
        LowLevelSaf.pushJsContext(jsGlobalContext);

        try {
          globalContexts.put(Integer.valueOf(jsGlobalObject),
              Integer.valueOf(jsGlobalContext));

          int external = LowLevelSaf.wrapDispatchObject(jsGlobalContext,
              new ExternalObject());
          LowLevelSaf.executeScript(jsGlobalContext,
              "function __defineExternal(x) {" + "  window.external = x;" + "}");
          int ignoredResult = LowLevelSaf.invoke(jsGlobalContext,
              jsGlobalObject, "__defineExternal", jsGlobalObject,
              new int[] {external});
          LowLevelSaf.gcUnprotect(jsGlobalContext, ignoredResult);
        } finally {
          LowLevelSaf.popJsContext(jsGlobalContext);
        }
      }

    });

    /*
     * HACK (knorton) - SWT wrapper on WebKit seems to cause unreliable repaints
     * when the DOM changes inside of WebView. To compensate for this, every
     * quarter second, we tell WebView to repaint itself fully.
     */
    getDisplay().timerExec(REDRAW_PERIOD, new Runnable() {
      public void run() {
        if (browser.isDisposed() || isDisposed()) {
          // stop running if we're disposed
          return;
        }
        // Force the browser to refresh
        browser.setNeedsDisplay(true);
        // Reschedule this object to run again
        getDisplay().timerExec(REDRAW_PERIOD, this);
      }
    });
  }

  @Override
  public String getUserAgent() {
    // See UserAgent.gwt.xml
    return "safari";
  }
}
TOP

Related Classes of com.google.gwt.dev.shell.mac.BrowserWidgetSaf

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.