This checkin has the basic functionality of NewWindowListener

re-implemented using the new event model.  It's a bit cleaner.

Next step is to uncomment the selection check at the end of
WindowCreatorTest.java.  This code currently causes the VM to crash.  I
also plan to do some testing on the chrome flags.

M classes_spec/org/mozilla/webclient/EventRegistration2.java

- deprecate {add,remove}NewWindowListener(), replace with
  setNewWindowListener().

M classes_spec/org/mozilla/webclient/NewWindowEvent.java

- added BrowserControl property, which the user sets into the event.

M classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java

- change newWindowListeners List ivar to newWindowListener ivar.

- fix {add,remove}NewWindowListener() to leverage setNewWindowListener()

- change nativeEventOccurred() to return an int instead of void.

- add boolean property nativeSetNewWindowListenerAttached()

M classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeEventThread.java

- modify pushBlockingWCRunnable() to execute the runnable right away if
  we're already on the NativeEventThread.  This is necessary to allow
  re-entrancy.

M src_moz/EmbedEventListener.cpp
M src_moz/EmbedEventListener.h

- expose the mEventRegistration ivar via a getter.

M src_moz/EventRegistrationImpl.cpp
M src_moz/NativeBrowserControl.cpp
M src_moz/NativeBrowserControl.h

- add nativeSetNewWindowListenerAttached(), which calls through and sets
  it on the NativeBrowserControl.

M src_moz/WindowCreator.cpp

- implement CreateChromeWindow2, which is called when the browser needs
  a new window.

M src_share/jni_util.cpp
M src_share/jni_util.h

- change util_SendEventToJava() to return int.

M test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java


git-svn-id: svn://10.0.0.236/trunk@167943 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
edburns%acm.org
2005-01-18 15:20:52 +00:00
parent 2a8426d8bb
commit 8a9f83057f
15 changed files with 257 additions and 90 deletions

View File

@@ -153,6 +153,7 @@
<classpath refid="test.classpath"/>
<formatter type="plain" usefile="false"/>
<test name="org.mozilla.webclient.BrowserControlFactoryTest"/>
<test name="org.mozilla.webclient.ProfileManagerTest"/>
<test name="org.mozilla.webclient.BookmarksTest"/>
@@ -164,8 +165,8 @@
<test name="org.mozilla.webclient.MouseListenerTest"/>
<test name="org.mozilla.webclient.KeyListenerTest"/>
<test name="org.mozilla.webclient.DocumentLoadListenerTest"/>
<!-- non running
<test name="org.mozilla.webclient.WindowCreatorTest"/>
<!-- non running
<test name="org.mozilla.webclient.wrapper_native.gtk.TestGtkBrowserControlCanvas"/>
-->

View File

@@ -26,8 +26,24 @@ import java.awt.event.KeyListener;
public interface EventRegistration2 extends EventRegistration {
public void addNewWindowListener(NewWindowListener listener);
public void removeNewWindowListener(NewWindowListener listener);
public void setNewWindowListener(NewWindowListener listener);
/**
* <p>Use {@link #setNewWindowListener} instead. Implementations must
* implement this method as a call to {@link #setNewWindowListener}
* passing null, followed by a call to {@link #setNewWindowListener}
* passing the argument listener.</p>
*
* @deprecated
*/
public void addNewWindowListener(NewWindowListener listener);
/**
* <p>Use {@link #setNewWindowListener} passing <code>null</code>.</p>
*
* @deprecated
*/
public void removeNewWindowListener(NewWindowListener listener);
public void addKeyListener(KeyListener listener);
public void removeKeyListener(KeyListener listener);

View File

@@ -35,4 +35,14 @@ public NewWindowEvent(Object source, long newType,
super(source, newType, newEventData);
}
protected BrowserControl browserControl;
public BrowserControl getBrowserControl() {
return browserControl;
}
public void setBrowserControl(BrowserControl newBrowserControl) {
browserControl = newBrowserControl;
}
} // end of class NewWindowEvent

View File

@@ -83,7 +83,7 @@ public class EventRegistrationImpl extends ImplObjectNative implements EventRegi
private List keyListeners;
private List newWindowListeners;
private NewWindowListener newWindowListener;
private BrowserToJavaEventPump eventPump = null;
@@ -109,7 +109,7 @@ public EventRegistrationImpl(WrapperFactory yourFactory,
documentLoadListeners = null;
mouseListeners = null;
keyListeners = null;
newWindowListeners = null;
newWindowListener = null;
eventPump = new BrowserToJavaEventPump(instanceCount++);
eventPump.start();
}
@@ -128,10 +128,7 @@ public void delete()
keyListeners.clear();
}
keyListeners = null;
if (null != newWindowListeners) {
newWindowListeners.clear();
}
newWindowListeners = null;
newWindowListener = null;
super.delete();
eventPump.stopRunning();
}
@@ -241,30 +238,38 @@ public void removeKeyListener(KeyListener listener)
}
}
public void addNewWindowListener(NewWindowListener listener)
{
ParameterCheck.nonNull(listener);
getWrapperFactory().verifyInitialized();
if (null == newWindowListeners) {
newWindowListeners = new ArrayList();
}
synchronized(newWindowListeners) {
newWindowListeners.add(listener);
}
public void addNewWindowListener(NewWindowListener listener) {
this.setNewWindowListener(null);
this.setNewWindowListener(listener);
}
public void removeNewWindowListener(NewWindowListener listener)
{
ParameterCheck.nonNull(listener);
getWrapperFactory().verifyInitialized();
synchronized(newWindowListeners) {
newWindowListeners.remove(listener);
}
public void removeNewWindowListener(NewWindowListener listener) {
this.setNewWindowListener(null);
}
public void setNewWindowListener(NewWindowListener listener)
{
getWrapperFactory().verifyInitialized();
synchronized(this) {
final boolean doClear = null == listener;
NativeEventThread.instance.pushBlockingWCRunnable(new WCRunnable(){
public Object run() {
if (doClear) {
nativeSetNewWindowListenerAttached(getNativeBrowserControl(),
false);
}
else {
nativeSetNewWindowListenerAttached(getNativeBrowserControl(),
true);
}
return null;
}
});
newWindowListener = listener;
}
}
/**
@@ -275,9 +280,10 @@ public void removeNewWindowListener(NewWindowListener listener)
*/
void nativeEventOccurred(String targetClassName, long eventType,
Object eventData)
int nativeEventOccurred(String targetClassName, long eventType,
Object eventData)
{
int rc = 0;
ParameterCheck.nonNull(targetClassName);
EventObject event = null;
@@ -294,12 +300,16 @@ void nativeEventOccurred(String targetClassName, long eventType,
event = createKeyEvent(eventType, eventData);
}
else if (NewWindowListener.class.getName().equals(targetClassName)) {
event = new NewWindowEvent(this, eventType, eventData);
NewWindowEvent newWindowEvent = new NewWindowEvent(this, eventType,
eventData);
newWindowListener.eventDispatched(newWindowEvent);
return getNativeBrowserControlFromNewWindowEvent(newWindowEvent);
}
// else...
eventPump.queueEvent(event);
eventPump.V();
return rc;
}
private EventObject createMouseEvent(long eventType, Object eventData) {
@@ -481,16 +491,45 @@ private EventObject createKeyEvent(long eventType, Object eventData) {
return event;
}
private int getNativeBrowserControlFromNewWindowEvent(NewWindowEvent event) {
BrowserControl newBrowserControl = null;
BrowserControlCanvas newCanvas = null;
EventRegistration2 newEventRegistration = null;
if (null == (newBrowserControl = event.getBrowserControl())) {
return 0;
}
try {
newEventRegistration = (EventRegistration2)
newBrowserControl.queryInterface(BrowserControl.EVENT_REGISTRATION_NAME);
}
catch (ClassNotFoundException cnf) {
// PENDING(edburns): correct logging story of root cause stack
// trace.
throw new IllegalStateException("Can't create new browser control in response to NewWindow event");
}
if (null == newEventRegistration) {
return 0;
}
return ((ImplObjectNative)newEventRegistration).getNativeBrowserControl();
}
private native void nativeSetCapturePageInfo(int webShellPtr,
boolean newState);
private native void nativeSetNewWindowListenerAttached(int webShellPtr,
boolean newState);
public class BrowserToJavaEventPump extends Thread {
private boolean keepRunning = false;
private List eventsToJava = null;
private int count = 0;
public BrowserToJavaEventPump(int instanceCount) {
super("BrowserToJavaEventPump-" + instanceCount);
eventsToJava = new ArrayList();
@@ -555,6 +594,10 @@ public class BrowserToJavaEventPump extends Thread {
((WebclientEvent)curEvent).getEventData() instanceof KeyEvent) {
listeners = EventRegistrationImpl.this.keyListeners;
}
else if (curEvent instanceof NewWindowEvent) {
EventRegistrationImpl.this.newWindowListener.eventDispatched((NewWindowEvent) curEvent);
continue;
}
// else...
if (null != curEvent && null != listeners) {

View File

@@ -82,8 +82,10 @@ public class NativeEventThread extends Thread {
WrapperFactory yourFactory,
int yourNativeWrapperFactory) {
super(threadName);
Assert.assert_it(null == instance);
instance = this;
// Don't do this check for subclasses
if (this.getClass() == NativeEventThread.class) {
instance = this;
}
ParameterCheck.nonNull(yourFactory);
wrapperFactory = yourFactory;
@@ -225,6 +227,12 @@ public void run()
Object pushBlockingWCRunnable(WCRunnable toInvoke) {
Object result = null;
RuntimeException e = null;
if (Thread.currentThread().getName().equals(instance.getName())){
result = toInvoke.run();
return result;
}
synchronized (this) {
blockingRunnables.push(toInvoke);
try {

View File

@@ -327,6 +327,17 @@ EmbedEventListener::SetEventRegistration(jobject yourEventRegistration)
return rv;
}
nsresult
EmbedEventListener::GetEventRegistration(jobject *_retval)
{
nsresult result = NS_ERROR_NULL_POINTER;
if (nsnull != _retval) {
*_retval = mEventRegistration;
result = NS_OK;
}
return result;
}
nsresult EmbedEventListener::PopulatePropertiesFromEvent(nsIDOMEvent *event)
{

View File

@@ -65,6 +65,7 @@ class EmbedEventListener : public nsIDOMKeyListener,
NS_IMETHOD MouseOut(nsIDOMEvent* aDOMEvent);
nsresult SetEventRegistration(jobject eventRegistration);
nsresult GetEventRegistration(jobject *_retval);
private:

View File

@@ -40,3 +40,11 @@ JNIEXPORT void JNICALL Java_org_mozilla_webclient_impl_wrapper_1native_EventRegi
}
JNIEXPORT void JNICALL Java_org_mozilla_webclient_impl_wrapper_1native_EventRegistrationImpl_nativeSetNewWindowListenerAttached
(JNIEnv *env, jobject obj, jint nativeBCPtr, jboolean newState)
{
NativeBrowserControl* nativeBrowserControl = (NativeBrowserControl *) nativeBCPtr;
nativeBrowserControl->SetNewWindowListenerAttached(newState);
}

View File

@@ -60,6 +60,7 @@ NativeBrowserControl::NativeBrowserControl(void)
mChromeLoaded = PR_FALSE;
mIsDestroyed = PR_FALSE;
mListenersAttached = PR_FALSE;
mNewWindowListenerAttached = PR_FALSE;
}
NativeBrowserControl::~NativeBrowserControl()
@@ -344,8 +345,25 @@ NativeBrowserControl::ContentStateChange(void)
AttachListeners();
}
}
nsresult
NativeBrowserControl::SetNewWindowListenerAttached(PRBool newState)
{
mNewWindowListenerAttached = newState;
return NS_OK;
}
nsresult
NativeBrowserControl::GetNewWindowListenerAttached(PRBool *_retval) {
nsresult result = NS_ERROR_NULL_POINTER;
if (nsnull != _retval) {
*_retval = mNewWindowListenerAttached;
result = NS_OK;
}
return result;
}
void
NativeBrowserControl::GetListener()
{

View File

@@ -87,6 +87,9 @@ public:
// attach event listeners.
void ContentStateChange (void);
nsresult SetNewWindowListenerAttached(PRBool newState);
nsresult GetNewWindowListenerAttached(PRBool *_retval);
private:
void GetListener (void);
@@ -134,6 +137,9 @@ public:
// is the chrome listener attached yet?
PRBool mListenersAttached;
// do we have a newWindowListener?
PRBool mNewWindowListenerAttached;
jobject mJavaBrowserControl;
NativeWrapperFactory * wrapperFactory;

View File

@@ -25,6 +25,10 @@
#include "nsIWebBrowser.h"
#include "WindowCreator.h"
#include "NativeBrowserControl.h"
#include "EmbedEventListener.h"
#include "EmbedWindow.h"
NativeBrowserControl* gNewWindowNativeBCPtr;
NS_IMPL_ISUPPORTS2(WindowCreator, nsIWindowCreator, nsIWindowCreator2)
@@ -87,37 +91,40 @@ WindowCreator::CreateChromeWindow2(nsIWebBrowserChrome *parent,
nsIURI *uri, PRBool *cancel,
nsIWebBrowserChrome **_retval)
{
nsresult rv = NS_OK;
PRBool hasNewWindowListener = PR_FALSE;
NativeBrowserControl *newNativeBrowserControl = nsnull;
jint newNativeBCPtr = -1;
JNIEnv *env = (JNIEnv *) JNU_GetEnv(gVm, JNI_VERSION);
rv = mNativeBCPtr->GetNewWindowListenerAttached(&hasNewWindowListener);
if (NS_FAILED(rv) || !hasNewWindowListener) {
return rv;
}
nsCOMPtr<nsIWebBrowser> webBrowser;
parent->GetWebBrowser(getter_AddRefs(webBrowser));
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(webBrowser));
if (nsnull != baseWindow) {
/*
Block this thread.
Call back into java and ask the user to create a top level
window and hand it, or an added child of it, to us. Call this
thing the userWindow.
Create a new BrowserControl, get its BrowserControlCanvas and
make it be a child of the userWindow.
Set the userWindow and the BrowserControlCanvas to visible ==
true. This is necessary to get the cause the underlying
mozilla window to be created.
java returns the C++ nativeBrowserControl to us. Cast it to a
native NativeBrowserControl C++ object instance. If the
nsIURI is non-null, cause the new window to navigate to that
URI. Return the NativeBrowserControl's EmbedWindow instance,
which is an impl of nsIWebBrowserChrome.
I'm not sure if it's safe to do all this on the same thread on
which mozilla calls us. I hope so.
*/
jobject eventRegistration = nsnull;
rv = mNativeBCPtr->mEventListener->GetEventRegistration(&eventRegistration);
if (NS_FAILED(rv) || !eventRegistration) {
return rv;
}
printf("debug: edburns: can QI to baseWindow\n\n");
// send this event to allow the user to create the new BrowserControl
newNativeBCPtr = util_SendEventToJava(nsnull,
eventRegistration,
NEW_WINDOW_LISTENER_CLASSNAME,
chromeFlags, nsnull);
newNativeBrowserControl = (NativeBrowserControl *) newNativeBCPtr;
PR_ASSERT(nsnull != newNativeBrowserControl);
nsCOMPtr<nsIWebBrowserChrome> webChrome(newNativeBrowserControl->mWindow);
*_retval = webChrome;
NS_IF_ADDREF(*_retval);
}
return NS_OK;

View File

@@ -383,10 +383,11 @@ void util_ThrowExceptionToJava (JNIEnv * env, const char * message)
}
} // ThrowExceptionToJava()
void util_SendEventToJava(JNIEnv *yourEnv, jobject eventRegistrationImpl,
jint util_SendEventToJava(JNIEnv *yourEnv, jobject eventRegistrationImpl,
jstring eventListenerClassName,
jlong eventType, jobject eventData)
{
jint rv = -1;
#ifdef BAL_INTERFACE
if (nsnull != externalEventOccurred) {
externalEventOccurred(yourEnv, eventRegistrationImpl,
@@ -394,13 +395,13 @@ void util_SendEventToJava(JNIEnv *yourEnv, jobject eventRegistrationImpl,
}
#else
if (nsnull == gVm) {
return;
return rv;
}
JNIEnv *env = (JNIEnv *) JNU_GetEnv(gVm, JNI_VERSION);
if (nsnull == env) {
return;
return rv;
}
jthrowable exception;
@@ -411,15 +412,16 @@ void util_SendEventToJava(JNIEnv *yourEnv, jobject eventRegistrationImpl,
jclass clazz = env->GetObjectClass(eventRegistrationImpl);
jmethodID mid = env->GetMethodID(clazz, "nativeEventOccurred",
"(Ljava/lang/String;JLjava/lang/Object;)V");
"(Ljava/lang/String;JLjava/lang/Object;)I");
if ( mid != nsnull) {
env->CallVoidMethod(eventRegistrationImpl, mid,
eventListenerClassName,
eventType, eventData);
rv = env->CallIntMethod(eventRegistrationImpl, mid,
eventListenerClassName,
eventType, eventData);
} else {
util_LogMessage(3, "cannot call the Java Method!\n");
}
#endif
return rv;
}
/**

View File

@@ -132,7 +132,6 @@ extern jstring MOUSE_LISTENER_CLASSNAME;
extern jstring KEY_LISTENER_CLASSNAME;
extern jstring NEW_WINDOW_LISTENER_CLASSNAME;
//
// Listener support
//
@@ -153,7 +152,6 @@ typedef enum {
#define KEY_LISTENER_CLASSNAME_VALUE "java.awt.event.KeyListener"
#define NEW_WINDOW_LISTENER_CLASSNAME_VALUE "org.mozilla.webclient.NewWindowListener"
#define START_DOCUMENT_LOAD_EVENT_MASK_VALUE "START_DOCUMENT_LOAD_EVENT_MASK"
#define END_DOCUMENT_LOAD_EVENT_MASK_VALUE "END_DOCUMENT_LOAD_EVENT_MASK"
#define START_URL_LOAD_EVENT_MASK_VALUE "START_URL_LOAD_EVENT_MASK"
@@ -263,7 +261,7 @@ void util_ThrowExceptionToJava (JNIEnv * env, const char * message);
*/
void util_SendEventToJava(JNIEnv *env, jobject eventRegistrationImpl,
jint util_SendEventToJava(JNIEnv *env, jobject eventRegistrationImpl,
jstring eventListenerClassName,
jlong eventType,
jobject eventData);

View File

@@ -1,5 +1,5 @@
/*
* $Id: WindowCreatorTest.java,v 1.1 2005-01-11 07:02:12 edburns%acm.org Exp $
* $Id: WindowCreatorTest.java,v 1.2 2005-01-18 15:20:52 edburns%acm.org Exp $
*/
/*
@@ -72,7 +72,7 @@ public class WindowCreatorTest extends WebclientTestCase {
static EventRegistration2 eventRegistration;
static CurrentPage2 currentPage = null;
static CurrentPage2 secondCurrentPage = null;
static boolean keepWaiting;
@@ -86,7 +86,12 @@ public class WindowCreatorTest extends WebclientTestCase {
public void testNewWindow() throws Exception {
BrowserControl firstBrowserControl = null;
DocumentLoadListenerImpl listener = null;
final DocumentLoadListenerImpl listener =
new DocumentLoadListenerImpl() {
public void doEndCheck() {
WindowCreatorTest.keepWaiting = false;
}
};
Selection selection = null;
firstBrowserControl = BrowserControlFactory.newBrowserControl();
assertNotNull(firstBrowserControl);
@@ -108,30 +113,50 @@ public class WindowCreatorTest extends WebclientTestCase {
Navigation2 nav = (Navigation2)
firstBrowserControl.queryInterface(BrowserControl.NAVIGATION_NAME);
assertNotNull(nav);
currentPage = (CurrentPage2)
firstBrowserControl.queryInterface(BrowserControl.CURRENT_PAGE_NAME);
assertNotNull(currentPage);
eventRegistration.addDocumentLoadListener(listener = new DocumentLoadListenerImpl() {
public void doEndCheck() {
WindowCreatorTest.keepWaiting = false;
}
});
eventRegistration.addDocumentLoadListener(listener);
final BitSet bitSet = new BitSet();
eventRegistration.addNewWindowListener(new NewWindowListener() {
public void eventDispatched(WebclientEvent event) {
eventRegistration.setNewWindowListener(new NewWindowListener() {
public void eventDispatched(WebclientEvent wcEvent) {
bitSet.set(0);
NewWindowEvent event = (NewWindowEvent) wcEvent;
BrowserControl secondBrowserControl = null;
BrowserControlCanvas secondCanvas = null;
EventRegistration2 secondEventRegistration = null;
try {
secondBrowserControl =
BrowserControlFactory.newBrowserControl();
secondCanvas = (BrowserControlCanvas)
secondBrowserControl.queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME);
secondEventRegistration =
(EventRegistration2)
secondBrowserControl.queryInterface(BrowserControl.EVENT_REGISTRATION_NAME);
secondCurrentPage = (CurrentPage2)
secondBrowserControl.queryInterface(BrowserControl.CURRENT_PAGE_NAME);
assertNotNull(secondCurrentPage);
} catch (Throwable e) {
System.out.println(e.getMessage());
fail();
}
secondEventRegistration.addDocumentLoadListener(listener);
event.setBrowserControl(secondBrowserControl);
Frame newFrame = new Frame();
newFrame.setUndecorated(true);
newFrame.setBounds(100, 100, 540, 380);
newFrame.add(secondCanvas, BorderLayout.CENTER);
newFrame.setVisible(true);
secondCanvas.setVisible(true);
}
});
Thread.currentThread().sleep(3000);
//
// load four files.
// load a file that pops up a new window on link click
//
WindowCreatorTest.keepWaiting = true;
@@ -149,9 +174,22 @@ public class WindowCreatorTest extends WebclientTestCase {
robot.mouseRelease(InputEvent.BUTTON1_MASK);
Thread.currentThread().sleep(3000);
assertTrue(!bitSet.isEmpty());
/***
// keep waiting until the previous load completes
while (WindowCreatorTest.keepWaiting) {
Thread.currentThread().sleep(1000);
}
assertNotNull(secondCurrentPage);
secondCurrentPage.selectAll();
selection = secondCurrentPage.getSelection();
assertTrue(-1 !=selection.toString().indexOf("This is page 1 of the WindowCreatorTest."));
**********/
frame.setVisible(false);
BrowserControlFactory.deleteBrowserControl(firstBrowserControl);
}

View File

@@ -7,7 +7,7 @@
<body>
<h1>WindowCreatorTest1</h1>
<p>This is page 1 of the history test.</p>
<p>This is page 1 of the WindowCreatorTest.</p>
<p><a href="WindowCreatorTest0.html" target="_">prev</a></p>