1 /*******************************************************************************
2  * Copyright (c) 2003, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *      John Reimer <terminal.node@gmail.com>
12  *******************************************************************************/
13 module org.eclipse.swt.browser.Mozilla;
14 
15 import java.lang.all;
16 
17 
18 version(Tango){
19     import tango.text.locale.Core;
20     import tango.sys.Environment;
21     import tango.stdc..string;
22 } else { // Phobos
23     import std.process: Environment = environment;
24 }
25 
26 //import org.eclipse.swt.internal.c.gtk;
27 
28 import org.eclipse.swt.SWT;
29 import org.eclipse.swt.SWTError;
30 import org.eclipse.swt.graphics.Device;
31 import org.eclipse.swt.graphics.Point;
32 import org.eclipse.swt.graphics.Rectangle;
33 
34 import org.eclipse.swt.browser.Browser;
35 import org.eclipse.swt.browser.WebBrowser;
36 import org.eclipse.swt.browser.MozillaDelegate;
37 import org.eclipse.swt.browser.AppFileLocProvider;
38 import org.eclipse.swt.browser.WindowCreator2;
39 import org.eclipse.swt.browser.PromptService2Factory;
40 import org.eclipse.swt.browser.HelperAppLauncherDialogFactory;
41 import org.eclipse.swt.browser.DownloadFactory;
42 import org.eclipse.swt.browser.DownloadFactory_1_8;
43 import org.eclipse.swt.browser.FilePickerFactory;
44 import org.eclipse.swt.browser.FilePickerFactory_1_8;
45 import org.eclipse.swt.browser.InputStream;
46 import org.eclipse.swt.browser.StatusTextEvent;
47 import org.eclipse.swt.browser.ProgressEvent;
48 import org.eclipse.swt.browser.LocationEvent;
49 import org.eclipse.swt.browser.WindowEvent;
50 import org.eclipse.swt.browser.TitleEvent;
51 
52 import org.eclipse.swt.internal.Compatibility;
53 import org.eclipse.swt.internal.LONG;
54 import org.eclipse.swt.internal.Library;
55 import org.eclipse.swt.internal.gtk.OS;
56 
57 import XPCOM = org.eclipse.swt.internal.mozilla.XPCOM;
58 import XPCOMInit = org.eclipse.swt.internal.mozilla.XPCOMInit;
59 
60 import org.eclipse.swt.internal.mozilla.Common;
61 import org.eclipse.swt.internal.mozilla.nsEmbedString;
62 import org.eclipse.swt.internal.mozilla.nsIAppShell;
63 import org.eclipse.swt.internal.mozilla.nsIBaseWindow;
64 import org.eclipse.swt.internal.mozilla.nsICategoryManager;
65 import org.eclipse.swt.internal.mozilla.nsIComponentManager;
66 import org.eclipse.swt.internal.mozilla.nsIComponentRegistrar;
67 import org.eclipse.swt.internal.mozilla.nsIContextMenuListener;
68 import org.eclipse.swt.internal.mozilla.nsICookie;
69 import org.eclipse.swt.internal.mozilla.nsICookieManager;
70 import org.eclipse.swt.internal.mozilla.nsID;
71 import org.eclipse.swt.internal.mozilla.nsIDOMNode;
72 import org.eclipse.swt.internal.mozilla.nsIDOMEvent;
73 import org.eclipse.swt.internal.mozilla.nsIDOMEventListener;
74 import org.eclipse.swt.internal.mozilla.nsIDOMEventTarget;
75 import org.eclipse.swt.internal.mozilla.nsIDOMKeyEvent;
76 import org.eclipse.swt.internal.mozilla.nsIDOMMouseEvent;
77 import org.eclipse.swt.internal.mozilla.nsIDOMSerializer;
78 import org.eclipse.swt.internal.mozilla.nsIDOMSerializer_1_7;
79 import org.eclipse.swt.internal.mozilla.nsIDOMWindow;
80 import org.eclipse.swt.internal.mozilla.nsIDOMWindowCollection;
81 import org.eclipse.swt.internal.mozilla.nsIDOMDocument;
82 import org.eclipse.swt.internal.mozilla.nsIDirectoryService;
83 import org.eclipse.swt.internal.mozilla.nsIDocShell;
84 import org.eclipse.swt.internal.mozilla.nsIEmbeddingSiteWindow;
85 import org.eclipse.swt.internal.mozilla.nsIFile;
86 import org.eclipse.swt.internal.mozilla.nsIFactory;
87 import org.eclipse.swt.internal.mozilla.nsIIOService;
88 import org.eclipse.swt.internal.mozilla.nsIInterfaceRequestor;
89 import org.eclipse.swt.internal.mozilla.nsIJSContextStack;
90 import org.eclipse.swt.internal.mozilla.nsILocalFile;
91 import org.eclipse.swt.internal.mozilla.nsIObserverService;
92 import org.eclipse.swt.internal.mozilla.nsIPrefBranch;
93 import org.eclipse.swt.internal.mozilla.nsIPrefLocalizedString;
94 import org.eclipse.swt.internal.mozilla.nsIPrefService;
95 import org.eclipse.swt.internal.mozilla.nsIProperties;
96 import org.eclipse.swt.internal.mozilla.nsIRequest;
97 import org.eclipse.swt.internal.mozilla.nsIServiceManager;
98 import org.eclipse.swt.internal.mozilla.nsISimpleEnumerator;
99 import org.eclipse.swt.internal.mozilla.nsIStreamListener;
100 import org.eclipse.swt.internal.mozilla.nsISupports;
101 import org.eclipse.swt.internal.mozilla.nsITooltipListener;
102 import org.eclipse.swt.internal.mozilla.nsIURI;
103 import org.eclipse.swt.internal.mozilla.nsIURIContentListener;
104 import org.eclipse.swt.internal.mozilla.nsIWeakReference;
105 import org.eclipse.swt.internal.mozilla.nsIWebBrowser;
106 import org.eclipse.swt.internal.mozilla.nsIWebBrowserChrome;
107 import org.eclipse.swt.internal.mozilla.nsIWebBrowserChromeFocus;
108 import org.eclipse.swt.internal.mozilla.nsIWebBrowserFocus;
109 import org.eclipse.swt.internal.mozilla.nsIWebNavigation;
110 import org.eclipse.swt.internal.mozilla.nsIWebNavigationInfo;
111 import org.eclipse.swt.internal.mozilla.nsIWebProgress;
112 import org.eclipse.swt.internal.mozilla.nsIWebProgressListener;
113 import org.eclipse.swt.internal.mozilla.nsIWindowWatcher;
114 import org.eclipse.swt.internal.mozilla.nsIWindowCreator;
115 import org.eclipse.swt.internal.mozilla.nsStringAPI;
116 
117 import org.eclipse.swt.layout.FillLayout;
118 import org.eclipse.swt.widgets.Composite;
119 import org.eclipse.swt.widgets.Display;
120 import org.eclipse.swt.widgets.Event;
121 import org.eclipse.swt.widgets.Label;
122 import org.eclipse.swt.widgets.Listener;
123 import org.eclipse.swt.widgets.Menu;
124 import org.eclipse.swt.widgets.Shell;
125 import org.eclipse.swt.widgets.Control;
126 
127 class Mozilla : WebBrowser, 
128                 nsIWeakReference, 
129                 nsIWebProgressListener, 
130                 nsIWebBrowserChrome,
131                 nsIWebBrowserChromeFocus, 
132                 nsIEmbeddingSiteWindow, 
133                 nsIInterfaceRequestor, 
134                 nsISupportsWeakReference, 
135                 nsIContextMenuListener, 
136                 nsIURIContentListener,
137                 nsITooltipListener, 
138                 nsIDOMEventListener {
139                     
140     GtkWidget* embedHandle;
141     nsIWebBrowser webBrowser;
142     Object webBrowserObject;
143     MozillaDelegate mozDelegate;
144 
145     int chromeFlags = nsIWebBrowserChrome.CHROME_DEFAULT;
146     int refCount, lastKeyCode, lastCharCode;
147     nsIRequest request;
148     Point location, size;
149     bool visible, isChild, ignoreDispose, awaitingNavigate;
150     Shell tip = null;
151     Listener listener;
152     nsIDOMWindow[] unhookedDOMWindows;
153 
154     static nsIAppShell AppShell;
155     static AppFileLocProvider LocationProvider;
156     static WindowCreator2 WindowCreator;
157     static int BrowserCount;
158     static bool Initialized, IsPre_1_8, PerformedVersionCheck, XPCOMWasGlued, XPCOMInitWasGlued;
159 
160     /* XULRunner detect constants */
161     static String GRERANGE_LOWER = "1.8.1.2"; //$NON-NLS-1$
162     static String GRERANGE_LOWER_FALLBACK = "1.8"; //$NON-NLS-1$
163     static const bool LowerRangeInclusive = true;
164     static String GRERANGE_UPPER = "1.9.*"; //$NON-NLS-1$
165     static const bool UpperRangeInclusive = true;
166 
167     static const int MAX_PORT = 65535;
168     static String SEPARATOR_OS(){
169         return System.getProperty ("file.separator"); //$NON-NLS-1$
170     }
171     static const String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
172     static const String DISPOSE_LISTENER_HOOKED = "org.eclipse.swt.browser.Mozilla.disposeListenerHooked"; //$NON-NLS-1$
173     static const String PREFIX_JAVASCRIPT = "javascript:"; //$NON-NLS-1$
174     static const String PREFERENCE_CHARSET = "intl.charset.default"; //$NON-NLS-1$
175     static const String PREFERENCE_DISABLEOPENDURINGLOAD = "dom.disable_open_during_load"; //$NON-NLS-1$
176     static const String PREFERENCE_DISABLEWINDOWSTATUSCHANGE = "dom.disable_window_status_change"; //$NON-NLS-1$
177     static const String PREFERENCE_LANGUAGES = "intl.accept_languages"; //$NON-NLS-1$
178     static const String PREFERENCE_PROXYHOST_FTP = "network.proxy.ftp"; //$NON-NLS-1$
179     static const String PREFERENCE_PROXYPORT_FTP = "network.proxy.ftp_port"; //$NON-NLS-1$
180     static const String PREFERENCE_PROXYHOST_HTTP = "network.proxy.http"; //$NON-NLS-1$
181     static const String PREFERENCE_PROXYPORT_HTTP = "network.proxy.http_port"; //$NON-NLS-1$
182     static const String PREFERENCE_PROXYHOST_SSL = "network.proxy.ssl"; //$NON-NLS-1$
183     static const String PREFERENCE_PROXYPORT_SSL = "network.proxy.ssl_port"; //$NON-NLS-1$
184     static const String PREFERENCE_PROXYTYPE = "network.proxy.type"; //$NON-NLS-1$
185     static const String PROFILE_AFTER_CHANGE = "profile-after-change"; //$NON-NLS-1$
186     static const String PROFILE_BEFORE_CHANGE = "profile-before-change"; //$NON-NLS-1$
187     static       String PROFILE_DIR; //= SEPARATOR_OS ~ "eclipse" ~ SEPARATOR_OS; //$NON-NLS-1$
188     static const String PROFILE_DO_CHANGE = "profile-do-change"; //$NON-NLS-1$
189     static const String PROPERTY_PROXYPORT = "network.proxy_port"; //$NON-NLS-1$
190     static const String PROPERTY_PROXYHOST = "network.proxy_host"; //$NON-NLS-1$
191     static const String SEPARATOR_LOCALE = "-"; //$NON-NLS-1$
192     static const String SHUTDOWN_PERSIST = "shutdown-persist"; //$NON-NLS-1$
193     static const String STARTUP = "startup"; //$NON-NLS-1$
194     static const String TOKENIZER_LOCALE = ","; //$NON-NLS-1$
195     static const String URI_FROMMEMORY = "file:///"; //$NON-NLS-1$
196     static const String XULRUNNER_PATH = "org.eclipse.swt.browser.XULRunnerPath"; //$NON-NLS-1$
197 
198     // TEMPORARY CODE
199     static const String GRE_INITIALIZED = "org.eclipse.swt.browser.XULRunnerInitialized"; //$NON-NLS-1$
200 
201     this () {
202         PROFILE_DIR = SEPARATOR_OS ~ "eclipse" ~ SEPARATOR_OS;
203         MozillaClearSessions = new class() Runnable {
204             public void run () {
205                 if (!Initialized) return;
206                 nsIServiceManager serviceManager;
207                 int rc = XPCOM.NS_GetServiceManager (&serviceManager);
208                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
209                 if (serviceManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
210 
211                 nsICookieManager manager;
212                 rc = serviceManager.GetServiceByContractID (XPCOM.NS_COOKIEMANAGER_CONTRACTID.ptr, &nsICookieManager.IID, cast(void**)&manager);
213                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
214                 if (manager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
215                 serviceManager.Release ();
216 
217                 nsISimpleEnumerator enumerator;
218                 rc = manager.GetEnumerator (&enumerator);
219                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
220                 manager.Release ();
221 
222                 PRBool moreElements;
223                 rc = enumerator.HasMoreElements (&moreElements);
224                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
225                 while (moreElements !is 0) {
226                     nsICookie cookie;
227                     rc = enumerator.GetNext (cast(nsISupports*)&cookie);
228                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
229                     PRUint64 expires;
230                     rc = cookie.GetExpires (&expires);
231                     if (expires is 0) {
232                         /* indicates a session cookie */
233                         scope auto domain = new nsEmbedCString;
234                         scope auto name = new nsEmbedCString;
235                         scope auto path = new nsEmbedCString;
236                         cookie.GetHost (cast(nsACString*)domain);
237                         cookie.GetName (cast(nsACString*)name);
238                         cookie.GetPath (cast(nsACString*)path);
239                         rc = manager.Remove (cast(nsACString*)domain, cast(nsACString*)name, cast(nsACString*)path, 0);
240                         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
241                     }
242                     cookie.Release ();
243                     rc = enumerator.HasMoreElements (&moreElements);
244                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
245                 }
246                 enumerator.Release ();
247             }
248         };
249     }
250 
251 extern(D)
252 public void create (Composite parent, int style) {
253     mozDelegate = new MozillaDelegate (super.browser);
254     Display display = parent.getDisplay ();
255 
256     if (!Initialized) {
257         bool initLoaded = false;
258         bool IsXULRunner = false;
259 
260         String greInitialized = System.getProperty (GRE_INITIALIZED); 
261         if ("true" == greInitialized) { //$NON-NLS-1$
262             /* 
263              * Another browser has already initialized xulrunner in this process,
264              * so just bind to it instead of trying to initialize a new one.
265              */
266             Initialized = true;
267         }
268         String mozillaPath = System.getProperty (XULRUNNER_PATH);
269         if (mozillaPath is null) {
270             // we don't need to load an initial library in D, so set to "true"
271             initLoaded = true;
272         } else {
273             mozillaPath ~= SEPARATOR_OS ~ mozDelegate.getLibraryName ();
274             IsXULRunner = true;
275         }
276          
277         if (initLoaded) {
278             /* attempt to discover a XULRunner to use as the GRE */
279             XPCOMInit.GREVersionRange range;
280 
281             range.lower = GRERANGE_LOWER.ptr;
282             range.lowerInclusive = LowerRangeInclusive;
283 
284             range.upper = GRERANGE_UPPER.ptr;
285             range.upperInclusive = UpperRangeInclusive;
286 
287             char[] greBuffer = new char[XPCOMInit.PATH_MAX];
288 
289             int rc = XPCOMInit.GRE_GetGREPathWithProperties (&range, 1, null, 0, greBuffer.ptr, greBuffer.length);
290 
291             /*
292              * A XULRunner was not found that supports wrapping of XPCOM handles as JavaXPCOM objects.
293              * Drop the lower version bound and try to detect an earlier XULRunner installation.
294              */
295 
296             if (rc !is XPCOM.NS_OK) {
297                 range.lower = GRERANGE_LOWER_FALLBACK.ptr;
298                 rc = XPCOMInit.GRE_GetGREPathWithProperties (&range, 1, null, 0, greBuffer.ptr, greBuffer.length);
299             }
300 
301             if (rc is XPCOM.NS_OK) {
302                 /* indicates that a XULRunner was found */
303                 mozillaPath = cast(String)greBuffer;
304                 IsXULRunner = mozillaPath.length > 0;
305 
306                 /*
307                  * Test whether the detected XULRunner can be used as the GRE before loading swt's
308                  * XULRunner library.  If it cannot be used then fall back to attempting to use
309                  * the GRE pointed to by MOZILLA_FIVE_HOME.
310                  * 
311                  * One case where this will fail is attempting to use a 64-bit xulrunner while swt
312                  * is running in 32-bit mode, or vice versa.
313                  */
314 
315                 if (IsXULRunner) {
316                     rc = XPCOMInit.XPCOMGlueStartup (mozillaPath.ptr);
317                     if (rc !is XPCOM.NS_OK) {
318                         mozillaPath = mozillaPath.substring (0, mozillaPath.lastIndexOf (SEPARATOR_OS));
319                         if (Device.DEBUG) getDwtLogger().error (__FILE__, __LINE__, "cannot use detected XULRunner: {}", mozillaPath); //$NON-NLS-1$
320                         
321                         /* attempt to XPCOMGlueStartup the GRE pointed at by MOZILLA_FIVE_HOME */
322                         auto ptr = Environment.get(XPCOM.MOZILLA_FIVE_HOME);
323                         
324                         if (ptr is null) {
325                             IsXULRunner = false;
326                         } else {
327                             mozillaPath = ptr;
328                             /*
329                              * Attempting to XPCOMGlueStartup a mozilla-based GRE !is xulrunner can
330                              * crash, so don't attempt unless the GRE appears to be xulrunner.
331                              */
332                             if (mozillaPath.indexOf("xulrunner") is -1) { //$NON-NLS-1$
333                                 IsXULRunner = false;    
334 
335                             } else {
336                                 mozillaPath ~= SEPARATOR_OS ~ mozDelegate.getLibraryName ();
337                                 rc = XPCOMInit.XPCOMGlueStartup (toStringz(mozillaPath));
338                                 if (rc !is XPCOM.NS_OK) {
339                                     IsXULRunner = false;
340                                     mozillaPath = mozillaPath.substring (0, mozillaPath.lastIndexOf (SEPARATOR_OS));
341                                     if (Device.DEBUG) getDwtLogger().error( __FILE__, __LINE__, "failed to start as XULRunner: {}", mozillaPath); //$NON-NLS-1$
342                                 }
343                             }
344                         } 
345                     }
346                     if (IsXULRunner) {
347                         XPCOMInitWasGlued = true;
348                     }
349                 }
350             }
351         }
352 
353         if (IsXULRunner) {
354             if (Device.DEBUG) getDwtLogger().error( __FILE__, __LINE__, "XULRunner path: {}", mozillaPath); //$NON-NLS-1$
355 
356             XPCOMWasGlued = true;
357 
358             /*
359              * Remove the trailing xpcom lib name from mozillaPath because the
360              * Mozilla.initialize and NS_InitXPCOM2 invocations require a directory name only.
361              */
362             mozillaPath = mozillaPath.substring (0, mozillaPath.lastIndexOf (SEPARATOR_OS));
363         } else {
364             if ((style & SWT.MOZILLA) !is 0) {
365                 browser.dispose ();
366                 String errorString = (mozillaPath !is null && mozillaPath.length > 0) ?
367                     " [Failed to use detected XULRunner: " ~ mozillaPath ~ "]" :
368                     " [Could not detect registered XULRunner to use]";  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
369                 SWT.error (SWT.ERROR_NO_HANDLES, null, errorString);
370             }
371 
372             /* attempt to use the GRE pointed at by MOZILLA_FIVE_HOME */
373             auto mozFiveHome = Environment.get(XPCOM.MOZILLA_FIVE_HOME);
374             if (mozFiveHome !is null) {
375                 mozillaPath = mozFiveHome;
376             } else {
377                 browser.dispose ();
378                 SWT.error (SWT.ERROR_NO_HANDLES, null, " [Unknown Mozilla path (MOZILLA_FIVE_HOME not set)]"); //$NON-NLS-1$
379             }
380             if (Device.DEBUG) getDwtLogger().error( __FILE__, __LINE__, "Mozilla path: {}", mozillaPath); //$NON-NLS-1$
381 
382             /*
383             * Note.  Embedding a Mozilla GTK1.2 causes a crash.  The workaround
384             * is to check the version of GTK used by Mozilla by looking for
385             * the libwidget_gtk.so library used by Mozilla GTK1.2. Mozilla GTK2
386             * uses the libwidget_gtk2.so library.   
387             */
388             if (Compatibility.fileExists (mozillaPath, "components/libwidget_gtk.so")) { //$NON-NLS-1$
389                 browser.dispose ();
390                 SWT.error (SWT.ERROR_NO_HANDLES, null, " [Mozilla GTK2 required (GTK1.2 detected)]"); //$NON-NLS-1$                         
391             }
392         }
393 
394         if (!Initialized) {
395             nsILocalFile localFile;
396             scope auto pathString = new nsEmbedString (mozillaPath.toWCharArray());
397             nsresult rc = XPCOM.NS_NewLocalFile (cast(nsAString*)pathString, 1, &localFile);
398             if (rc !is XPCOM.NS_OK) {
399                 browser.dispose ();
400                 error (rc, __FILE__, __LINE__);
401             }
402             if (localFile is null) {
403                 browser.dispose ();
404                 error (XPCOM.NS_ERROR_NULL_POINTER);
405             }
406 
407             LocationProvider = new AppFileLocProvider (mozillaPath);
408             LocationProvider.AddRef ();
409 
410             nsIDirectoryServiceProvider directoryServiceProvider;
411             rc = LocationProvider.QueryInterface( &nsIDirectoryServiceProvider.IID, cast(void**)&directoryServiceProvider);
412             if (rc !is XPCOM.NS_OK) {
413                 browser.dispose();
414                 error(rc);
415             }
416             rc = XPCOM.NS_InitXPCOM2 (null, cast(nsIFile)localFile, directoryServiceProvider);
417             localFile.Release ();
418             LocationProvider.Release();
419             if (rc !is XPCOM.NS_OK) {
420                 browser.dispose ();
421                 SWT.error (SWT.ERROR_NO_HANDLES, null, Format(" [MOZILLA_FIVE_HOME may not point at an embeddable GRE] [NS_InitEmbedding {0} error {1} ] ", mozillaPath, rc ) ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
422             }
423             System.setProperty (GRE_INITIALIZED, "true"); //$NON-NLS-1$
424             if (IsXULRunner) {
425                 System.setProperty (XULRUNNER_PATH, mozillaPath);
426             }
427         }
428 
429         nsIComponentManager componentManager;
430         int rc = XPCOM.NS_GetComponentManager (&componentManager);
431         if (rc !is XPCOM.NS_OK) {
432             browser.dispose ();
433             error (rc, __FILE__, __LINE__);
434         }
435         if (componentManager is null) {
436             browser.dispose ();
437             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
438         }
439         
440         if (mozDelegate.needsSpinup ()) {
441             /* nsIAppShell is discontinued as of xulrunner 1.9, so do not fail if it is not found */
442             rc = componentManager.CreateInstance (&XPCOM.NS_APPSHELL_CID, null, &nsIAppShell.IID, cast(void**)&AppShell);
443             if (rc !is XPCOM.NS_ERROR_NO_INTERFACE) {
444                 if (rc !is XPCOM.NS_OK) {
445                     browser.dispose ();
446                     error (rc, __FILE__, __LINE__);
447                 }
448                 if (AppShell is null) {
449                     browser.dispose ();
450                     error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
451                 }
452     
453                 rc = AppShell.Create (null, null);
454                 if (rc !is XPCOM.NS_OK) {
455                     browser.dispose ();
456                     error (rc, __FILE__, __LINE__);
457                 }
458                 rc = AppShell.Spinup ();
459                 if (rc !is XPCOM.NS_OK) {
460                     browser.dispose ();
461                     error (rc, __FILE__, __LINE__);
462                 }
463             }
464         }
465 
466         WindowCreator = new WindowCreator2;
467         WindowCreator.AddRef ();
468         
469         nsIServiceManager serviceManager;
470         rc = XPCOM.NS_GetServiceManager (&serviceManager);
471         if (rc !is XPCOM.NS_OK) {
472             browser.dispose ();
473             error (rc, __FILE__, __LINE__);
474         }
475         if (serviceManager is null) {
476             browser.dispose ();
477             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
478         }
479         
480         nsIWindowWatcher windowWatcher;
481         rc = serviceManager.GetServiceByContractID (XPCOM.NS_WINDOWWATCHER_CONTRACTID.ptr, &nsIWindowWatcher.IID, cast(void**)&windowWatcher);
482         if (rc !is XPCOM.NS_OK) {
483             browser.dispose ();
484             error (rc, __FILE__, __LINE__);
485         }
486         if (windowWatcher is null) {
487             browser.dispose ();
488             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);       
489         }
490 
491         rc = windowWatcher.SetWindowCreator (cast(nsIWindowCreator)WindowCreator);
492         if (rc !is XPCOM.NS_OK) {
493             browser.dispose ();
494             error (rc, __FILE__, __LINE__);
495         }
496         windowWatcher.Release ();
497 
498         if (LocationProvider !is null) {
499             nsIDirectoryService directoryService;
500             rc = serviceManager.GetServiceByContractID (XPCOM.NS_DIRECTORYSERVICE_CONTRACTID.ptr, &nsIDirectoryService.IID, cast(void**)&directoryService);
501             if (rc !is XPCOM.NS_OK) {
502                 browser.dispose ();
503                 error (rc, __FILE__, __LINE__);
504             }
505             if (directoryService is null) {
506                 browser.dispose ();
507                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
508             }
509 
510             nsIProperties properties;
511             rc = directoryService.QueryInterface (&nsIProperties.IID, cast(void**)&properties);
512             if (rc !is XPCOM.NS_OK) {
513                 browser.dispose ();
514                 error (rc, __FILE__, __LINE__);
515             }
516             if (properties is null) {
517                 browser.dispose ();
518                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
519             }
520             directoryService.Release ();
521 
522             nsIFile profileDir;
523             rc = properties.Get (XPCOM.NS_APP_APPLICATION_REGISTRY_DIR.ptr, &nsIFile.IID, cast(void**)&profileDir);
524             if (rc !is XPCOM.NS_OK) {
525                 browser.dispose ();
526                 error (rc, __FILE__, __LINE__);
527             }
528             if (profileDir is null) {
529                 browser.dispose ();
530                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
531             }
532             properties.Release ();
533 
534             scope auto path = new nsEmbedCString;
535             rc = profileDir.GetNativePath (cast(nsACString*)path);
536             if (rc !is XPCOM.NS_OK) {
537                 browser.dispose ();
538                 error (rc, __FILE__, __LINE__);
539             }
540 
541             String profilePath = path.toString() ~ PROFILE_DIR;
542             LocationProvider.setProfilePath (profilePath);
543             LocationProvider.isXULRunner = IsXULRunner;
544 
545             profileDir.Release ();
546 
547             /* notify observers of a new profile directory being used */
548             nsIObserverService observerService;
549             rc = serviceManager.GetServiceByContractID (XPCOM.NS_OBSERVER_CONTRACTID.ptr, &nsIObserverService.IID, cast(void**)&observerService);
550             if (rc !is XPCOM.NS_OK) {
551                 browser.dispose ();
552                 error (rc, __FILE__, __LINE__);
553             }
554             if (observerService is null) {
555                 browser.dispose ();
556                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
557             }
558 
559             wchar* chars = STARTUP.toWCharArray().toString16z();
560             rc = observerService.NotifyObservers (null, PROFILE_DO_CHANGE.ptr, chars);
561             if (rc !is XPCOM.NS_OK) {
562                 browser.dispose ();
563                 error (rc, __FILE__, __LINE__);
564             }
565 
566             rc = observerService.NotifyObservers (null, PROFILE_AFTER_CHANGE.ptr, chars);
567             if (rc !is XPCOM.NS_OK) {
568                 browser.dispose ();
569                 error (rc, __FILE__, __LINE__);
570             }
571             observerService.Release ();
572         }
573 
574         /*
575          * As a result of using a common profile the user cannot change their locale
576          * and charset.  The fix for this is to set mozilla's locale and charset
577          * preference values according to the user's current locale and charset.
578          */
579 
580         nsIPrefService prefService;
581         rc = serviceManager.GetServiceByContractID (XPCOM.NS_PREFSERVICE_CONTRACTID.ptr, &nsIPrefService.IID, cast(void**)&prefService);
582         serviceManager.Release ();
583         if (rc !is XPCOM.NS_OK) {
584             browser.dispose ();
585             error (rc, __FILE__, __LINE__);
586         }
587         if (serviceManager is null) {
588             browser.dispose ();
589             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
590         }
591 
592         char[1] buffer = new char[1];
593         nsIPrefBranch prefBranch;
594         rc = prefService.GetBranch (buffer.ptr, &prefBranch);    /* empty buffer denotes root preference level */
595         prefService.Release ();
596         if (rc !is XPCOM.NS_OK) {
597             browser.dispose ();
598             error (rc, __FILE__, __LINE__);
599         }
600         if (prefBranch is null) {
601             browser.dispose ();
602             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
603         }
604 
605         /* get Mozilla's current locale preference value */
606         String prefLocales = null;
607         nsIPrefLocalizedString localizedString = null;
608         //buffer = MozillaDelegate.wcsToMbcs (null, PREFERENCE_LANGUAGES, true);
609         rc = prefBranch.GetComplexValue (PREFERENCE_LANGUAGES.ptr, &nsIPrefLocalizedString.IID, cast(void**)&localizedString);
610         /* 
611          * Feature of Debian.  For some reason attempting to query for the current locale
612          * preference fails on Debian.  The workaround for this is to assume a value of
613          * "en-us,en" since this is typically the default value when mozilla is used without
614          * a profile.
615          */
616         if (rc !is XPCOM.NS_OK) {
617             prefLocales = "en-us,en" ~ TOKENIZER_LOCALE;    //$NON-NLS-1$
618         } else {
619             if (localizedString is null) {
620                 browser.dispose ();
621                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
622             }
623             PRUnichar* tmpChars;
624             rc = localizedString.ToString (&tmpChars);
625             if (rc !is XPCOM.NS_OK) {
626                 browser.dispose ();
627                 error (rc, __FILE__, __LINE__);
628             }
629             if (tmpChars is null) {
630                 browser.dispose ();
631                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
632             }
633             int span = XPCOM.strlen_PRUnichar (tmpChars);
634             prefLocales = String_valueOf(tmpChars[0 .. span]) ~ TOKENIZER_LOCALE;
635         }
636 
637         /*
638          * construct the new locale preference value by prepending the
639          * user's current locale and language to the original value 
640          */
641 
642         version(Tango){
643             String language = Culture.current.twoLetterLanguageName ();
644             String country = Region.current.twoLetterRegionName ();
645         } else { // Phobos
646             implMissingInPhobos();
647             String language = "en";
648             String country = "us";
649         }
650         String stringBuffer = language._idup();
651 
652         stringBuffer ~= SEPARATOR_LOCALE;
653         stringBuffer ~= country.toLowerCase ();
654         stringBuffer ~= TOKENIZER_LOCALE;
655         stringBuffer ~= language;
656         stringBuffer ~= TOKENIZER_LOCALE;
657         String newLocales = stringBuffer._idup();
658 
659         int start, end = -1;
660         do {
661             start = end + 1;
662             end = prefLocales.indexOf (TOKENIZER_LOCALE, start);
663             String token;
664             if (end is -1) {
665                 token = prefLocales.substring (start);
666             } else {
667                 token = prefLocales.substring (start, end);
668             }
669             if (token.length () > 0) {
670                 token = (token ~ TOKENIZER_LOCALE).trim ();
671                 /* ensure that duplicate locale values are not added */
672                 if (newLocales.indexOf (token) is -1) {
673                     stringBuffer ~= token;
674                 }
675             }
676         } while (end !is -1);
677         (cast(char[])newLocales)[] = stringBuffer[];
678         if (!newLocales.equals (prefLocales)) {
679             /* write the new locale value */
680             newLocales = newLocales.substring (0, newLocales.length () - TOKENIZER_LOCALE.length ()); /* remove trailing tokenizer */
681             if (localizedString is null) {
682                 rc = componentManager.CreateInstanceByContractID (XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID.ptr, null, &nsIPrefLocalizedString.IID, cast(void**)&localizedString);
683                 if (rc !is XPCOM.NS_OK) {
684                     browser.dispose ();
685                     error (rc, __FILE__, __LINE__);
686                 }
687                 if (localizedString is null) {
688                     browser.dispose ();
689                     error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
690                 }
691             }
692             localizedString.SetDataWithLength (newLocales.length, newLocales.toWCharArray().toString16z());
693             rc = prefBranch.SetComplexValue (PREFERENCE_LANGUAGES.ptr, &nsIPrefLocalizedString.IID, cast(nsISupports)localizedString);
694         }
695         if (localizedString !is null) {
696             localizedString.Release ();
697             localizedString = null;
698         }
699 
700         /* get Mozilla's current charset preference value */
701         String prefCharset = null;
702         rc = prefBranch.GetComplexValue (PREFERENCE_CHARSET.ptr, &nsIPrefLocalizedString.IID, cast(void**)&localizedString);
703         /* 
704          * Feature of Debian.  For some reason attempting to query for the current charset
705          * preference fails on Debian.  The workaround for this is to assume a value of
706          * "ISO-8859-1" since this is typically the default value when mozilla is used
707          * without a profile.
708          */
709         if (rc !is XPCOM.NS_OK) {
710             prefCharset = "ISO-8859-1"; //$NON_NLS-1$
711         } else {
712             if (localizedString is null) {
713                 browser.dispose ();
714                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
715             }
716             PRUnichar* tmpChar;
717             rc = localizedString.ToString (&tmpChar);
718             if (rc !is XPCOM.NS_OK) {
719                 browser.dispose ();
720                 error (rc, __FILE__, __LINE__);
721             }
722             if (tmpChar is null) {
723                 browser.dispose ();
724                 error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
725             }
726             int span = XPCOM.strlen_PRUnichar (tmpChar);
727             prefCharset = String_valueOf(tmpChar[0 .. span]);
728         }
729 
730         String newCharset = System.getProperty ("file.encoding");   // $NON-NLS-1$
731         if (!newCharset.equals (prefCharset)) {
732             /* write the new charset value */
733             if (localizedString is null) {
734                 rc = componentManager.CreateInstanceByContractID (XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID.ptr, null, &nsIPrefLocalizedString.IID, cast(void**)&localizedString);
735                 if (rc !is XPCOM.NS_OK) {
736                     browser.dispose ();
737                     error (rc, __FILE__, __LINE__);
738                 }
739                 if (localizedString is null) {
740                     browser.dispose ();
741                     error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
742                 }
743             }
744             localizedString.SetDataWithLength (newCharset.length, newCharset.toWCharArray().toString16z());
745             rc = prefBranch.SetComplexValue (PREFERENCE_CHARSET.ptr, &nsIPrefLocalizedString.IID, cast(nsISupports)localizedString);
746         }
747         if (localizedString !is null) localizedString.Release ();
748 
749         /*
750         * Check for proxy values set as documented java properties and update mozilla's
751         * preferences with these values if needed.
752         */
753 
754         // NOTE: in org.eclipse.swt, these properties don't exist so both keys will return null
755         // (which appears to be ok in this situaion)
756         String proxyHost = System.getProperty (PROPERTY_PROXYHOST);
757         String proxyPortString = System.getProperty (PROPERTY_PROXYPORT);
758 
759         int port = -1;
760         if (proxyPortString !is null) {
761             try {
762                 int value = Integer.valueOf (proxyPortString).intValue ();
763                 if (0 <= value && value <= MAX_PORT) port = value;
764             } catch (NumberFormatException e) {
765                 /* do nothing, java property has non-integer value */
766             }
767         }
768 
769         if (proxyHost !is null) {
770             rc = componentManager.CreateInstanceByContractID (XPCOM.NS_PREFLOCALIZEDSTRING_CONTRACTID.ptr, null, &nsIPrefLocalizedString.IID, cast(void**)&localizedString);
771             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
772             if (localizedString is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
773 
774             rc = localizedString.SetDataWithLength (proxyHost.length, proxyHost.toWCharArray().toString16z());
775             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
776             rc = prefBranch.SetComplexValue (PREFERENCE_PROXYHOST_FTP.ptr, &nsIPrefLocalizedString.IID, cast(nsISupports)localizedString);
777             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
778             rc = prefBranch.SetComplexValue (PREFERENCE_PROXYHOST_HTTP.ptr, &nsIPrefLocalizedString.IID, cast(nsISupports)localizedString);
779             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
780             rc = prefBranch.SetComplexValue (PREFERENCE_PROXYHOST_SSL.ptr, &nsIPrefLocalizedString.IID, cast(nsISupports)localizedString);
781             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
782             localizedString.Release ();
783         }
784 
785         if (port !is -1) {
786             rc = prefBranch.SetIntPref (PREFERENCE_PROXYPORT_FTP.ptr, port);
787             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
788             rc = prefBranch.SetIntPref (PREFERENCE_PROXYPORT_HTTP.ptr, port);
789             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
790             rc = prefBranch.SetIntPref (PREFERENCE_PROXYPORT_SSL.ptr, port);
791             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
792         }
793 
794         if (proxyHost !is null || port !is -1) {
795             rc = prefBranch.SetIntPref (PREFERENCE_PROXYTYPE.ptr, 1);
796             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
797         }
798 
799         /*
800         * Ensure that windows that are shown during page loads are not blocked.  Firefox may
801         * try to block these by default since such windows are often unwelcome, but this
802         * assumption should not be made in the Browser's context.  Since the Browser client
803         * is responsible for creating the new Browser and Shell in an OpenWindowListener,
804         * they should decide whether the new window is unwelcome or not and act accordingly. 
805         */
806         rc = prefBranch.SetBoolPref (PREFERENCE_DISABLEOPENDURINGLOAD.ptr, 0);
807         if (rc !is XPCOM.NS_OK) {
808             browser.dispose ();
809             error (rc, __FILE__, __LINE__);
810         }
811 
812         /* Ensure that the status text can be set through means like javascript */ 
813         rc = prefBranch.SetBoolPref (PREFERENCE_DISABLEWINDOWSTATUSCHANGE.ptr, 0);
814         if (rc !is XPCOM.NS_OK) {
815             browser.dispose ();
816             error (rc, __FILE__, __LINE__);
817         }
818 
819         prefBranch.Release ();
820 
821         PromptService2Factory factory = new PromptService2Factory ();
822         factory.AddRef ();
823 
824         nsIComponentRegistrar componentRegistrar;
825         rc = componentManager.QueryInterface (&nsIComponentRegistrar.IID, cast(void**)&componentRegistrar);
826         if (rc !is XPCOM.NS_OK) {
827             browser.dispose ();
828             error (rc, __FILE__, __LINE__);
829         }
830         if (componentRegistrar is null) {
831             browser.dispose ();
832             error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
833         }
834         
835         String aClassName = "Prompt Service"; 
836 
837         rc = componentRegistrar.RegisterFactory (&XPCOM.NS_PROMPTSERVICE_CID, aClassName.ptr, XPCOM.NS_PROMPTSERVICE_CONTRACTID.ptr, cast(nsIFactory)factory);
838 
839         if (rc !is XPCOM.NS_OK) {
840             browser.dispose ();
841             error (rc, __FILE__, __LINE__);
842         }
843         factory.Release ();
844 
845         /*
846         * This Download factory will be used if the GRE version is < 1.8.
847         * If the GRE version is 1.8.x then the Download factory that is registered later for
848         *   contract "Transfer" will be used.
849         * If the GRE version is >= 1.9 then no Download factory is registered because this
850         *   functionality is provided by the GRE.
851         */
852         DownloadFactory downloadFactory = new DownloadFactory ();
853         downloadFactory.AddRef ();
854         aClassName = "Download";
855         rc = componentRegistrar.RegisterFactory (&XPCOM.NS_DOWNLOAD_CID, aClassName.ptr, XPCOM.NS_DOWNLOAD_CONTRACTID.ptr, cast(nsIFactory)downloadFactory);
856         if (rc !is XPCOM.NS_OK) {
857             browser.dispose ();
858             error (rc, __FILE__, __LINE__);
859         }
860         downloadFactory.Release ();
861 
862         FilePickerFactory pickerFactory = IsXULRunner ? new FilePickerFactory_1_8 () : new FilePickerFactory ();
863         pickerFactory.AddRef ();
864         aClassName = "FilePicker";
865         rc = componentRegistrar.RegisterFactory (&XPCOM.NS_FILEPICKER_CID, aClassName.ptr, XPCOM.NS_FILEPICKER_CONTRACTID.ptr, cast(nsIFactory)pickerFactory);
866         if (rc !is XPCOM.NS_OK) {
867             browser.dispose ();
868             error (rc, __FILE__, __LINE__);
869         }
870         pickerFactory.Release ();
871 
872         componentRegistrar.Release ();
873         componentManager.Release ();
874 
875         Initialized = true;
876     }
877 
878     if (display.getData (DISPOSE_LISTENER_HOOKED) is null) {
879         display.setData (DISPOSE_LISTENER_HOOKED, stringcast(DISPOSE_LISTENER_HOOKED));
880         display.addListener (SWT.Dispose, dgListener( &handleDisposeEvent, display )  );
881     }
882 
883     BrowserCount++;
884     nsIComponentManager componentManager;
885     int rc = XPCOM.NS_GetComponentManager (&componentManager);
886     if (rc !is XPCOM.NS_OK) {
887         browser.dispose ();
888         error (rc, __FILE__, __LINE__);
889     }
890     if (componentManager is null) {
891         browser.dispose ();
892         error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
893     }
894     
895     nsID NS_IWEBBROWSER_CID = { 0xF1EAC761, 0x87E9, 0x11d3, [0xAF, 0x80, 0x00, 0xA0, 0x24, 0xFF, 0xC0, 0x8C] }; //$NON-NLS-1$
896     rc = componentManager.CreateInstance (&NS_IWEBBROWSER_CID, null, &nsIWebBrowser.IID, cast(void**)&webBrowser);
897     if (rc !is XPCOM.NS_OK) {
898         browser.dispose ();
899         error (rc, __FILE__, __LINE__);
900     }
901     if (webBrowser is null) {
902         browser.dispose ();
903         error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);   
904     }
905     
906     this.AddRef ();
907 
908     rc = webBrowser.SetContainerWindow ( cast(nsIWebBrowserChrome)this );
909     if (rc !is XPCOM.NS_OK) {
910         browser.dispose ();
911         error (rc, __FILE__, __LINE__);
912     }
913             
914     nsIBaseWindow baseWindow;
915     rc = webBrowser.QueryInterface (&nsIBaseWindow.IID, cast(void**)&baseWindow);
916     if (rc !is XPCOM.NS_OK) {
917         browser.dispose ();
918         error (rc, __FILE__, __LINE__);
919     }
920     if (baseWindow is null) {
921         browser.dispose ();
922         error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
923     }
924     
925     Rectangle rect = browser.getClientArea ();
926     if (rect.isEmpty ()) {
927         rect.width = 1;
928         rect.height = 1;
929     }
930 
931     embedHandle = mozDelegate.getHandle ();
932 
933     rc = baseWindow.InitWindow (cast(void*)embedHandle, null, 0, 0, rect.width, rect.height);
934     if (rc !is XPCOM.NS_OK) {
935         browser.dispose ();
936         error (XPCOM.NS_ERROR_FAILURE);
937     }
938     rc = baseWindow.Create ();
939     if (rc !is XPCOM.NS_OK) {
940         browser.dispose ();
941         error (XPCOM.NS_ERROR_FAILURE);
942     }
943     rc = baseWindow.SetVisibility (1);
944     if (rc !is XPCOM.NS_OK) {
945         browser.dispose ();
946         error (XPCOM.NS_ERROR_FAILURE);
947     }
948     baseWindow.Release ();
949 
950     if (!PerformedVersionCheck) {
951         PerformedVersionCheck = true;
952         
953         nsIComponentRegistrar componentRegistrar;
954         rc = componentManager.QueryInterface (&nsIComponentRegistrar.IID, cast(void**)&componentRegistrar);
955         if (rc !is XPCOM.NS_OK) {
956             browser.dispose ();
957             error (rc, __FILE__,__LINE__);
958         }
959         if (componentRegistrar is null) {
960             browser.dispose ();
961             error (XPCOM.NS_NOINTERFACE,__FILE__,__LINE__);
962         }
963 
964         HelperAppLauncherDialogFactory dialogFactory = new HelperAppLauncherDialogFactory ();
965         dialogFactory.AddRef ();
966         String aClassName = "Helper App Launcher Dialog"; //$NON-NLS-1$
967         rc = componentRegistrar.RegisterFactory (&XPCOM.NS_HELPERAPPLAUNCHERDIALOG_CID, aClassName.ptr, XPCOM.NS_HELPERAPPLAUNCHERDIALOG_CONTRACTID.ptr, cast(nsIFactory)dialogFactory);
968         if (rc !is XPCOM.NS_OK) {
969             browser.dispose ();
970             error (rc,__FILE__,__LINE__);
971         }
972         dialogFactory.Release ();
973 
974         /*
975         * Check for the availability of the pre-1.8 implementation of nsIDocShell
976         * to determine if the GRE's version is < 1.8.
977         */
978         nsIInterfaceRequestor interfaceRequestor;
979         rc = webBrowser.QueryInterface (&nsIInterfaceRequestor.IID, cast(void**)&interfaceRequestor);
980         if (rc !is XPCOM.NS_OK) {
981             browser.dispose ();
982             error (XPCOM.NS_ERROR_FAILURE);
983         }
984         if (interfaceRequestor is null) {
985             browser.dispose ();
986             error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
987         }
988 
989         nsIDocShell docShell;
990         rc = interfaceRequestor.GetInterface (&nsIDocShell.IID, cast(void**)&docShell);
991         if (rc is XPCOM.NS_OK && docShell !is null) {
992             IsPre_1_8 = true;
993             docShell.Release ();
994         }
995 
996         /*
997         * A Download factory for contract "Transfer" must be registered iff the GRE's version is 1.8.x.
998         *   Check for the availability of the 1.8 implementation of nsIDocShell to determine if the
999         *   GRE's version is 1.8.x.
1000         * If the GRE version is < 1.8 then the previously-registered Download factory for contract
1001         *   "Download" will be used.
1002         * If the GRE version is >= 1.9 then no Download factory is registered because this
1003         *   functionality is provided by the GRE.
1004         */
1005         if (!IsPre_1_8) {
1006             nsIDocShell_1_8 docShell_1_8;
1007             rc = interfaceRequestor.GetInterface (&nsIDocShell_1_8.IID, cast(void**)&docShell_1_8);
1008             if (rc is XPCOM.NS_OK && docShell_1_8 !is null) { /* 1.8 */
1009                 docShell_1_8.Release ();
1010  
1011                 DownloadFactory_1_8 downloadFactory_1_8 = new DownloadFactory_1_8 ();
1012                 downloadFactory_1_8.AddRef ();
1013                 
1014                 aClassName = "Transfer"; //$NON-NLS-1$
1015                 rc = componentRegistrar.RegisterFactory (&XPCOM.NS_DOWNLOAD_CID, aClassName.ptr, XPCOM.NS_TRANSFER_CONTRACTID.ptr, cast(nsIFactory)downloadFactory_1_8);
1016                 if (rc !is XPCOM.NS_OK) {
1017                     browser.dispose ();
1018                     error (rc, __FILE__, __LINE__);
1019                 }
1020                 downloadFactory_1_8.Release ();
1021                 } else { /* >= 1.9 */
1022                 /*
1023                  * Bug in XULRunner 1.9.  Mozilla no longer clears its background before initial content has
1024                  * been set.  As a result embedders appear broken if they do not immediately navigate to a url.
1025                  * The workaround for this is to navigate to about:blank immediately so that the background is
1026                  * cleared, but do not fire any corresponding events or allow Browser API calls to reveal this.
1027                  * Once the client does a proper navigate with either setUrl() or setText() then resume as
1028                  * normal.  The Mozilla bug for this is https://bugzilla.mozilla.org/show_bug.cgi?id=415789.
1029                  */
1030                 awaitingNavigate = true;
1031                 nsIWebNavigation webNavigation;
1032                 rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1033                 if (rc !is XPCOM.NS_OK) {
1034                     browser.dispose ();
1035                     error (rc, __FILE__, __LINE__);
1036                 }
1037                 if (webNavigation is null) {
1038                     browser.dispose ();
1039                     error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1040                 }
1041                 rc = webNavigation.LoadURI (ABOUT_BLANK.toWCharArray().toString16z(), nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
1042                 webNavigation.Release ();
1043                 dialogFactory.isPre_1_9 = false;
1044             }
1045         }
1046         interfaceRequestor.Release ();
1047         componentRegistrar.Release ();
1048     }
1049     componentManager.Release ();
1050 
1051     rc = webBrowser.AddWebBrowserListener (cast(nsIWeakReference)this, &nsIWebProgressListener.IID);
1052     if (rc !is XPCOM.NS_OK) {
1053         browser.dispose ();
1054         error (rc, __FILE__, __LINE__);
1055     }
1056 
1057     // TODO: Find appropriate place to "Release" uriContentListener -JJR
1058     nsIURIContentListener uriContentListener;
1059     this.QueryInterface(&nsIURIContentListener.IID, cast(void**)&uriContentListener);
1060     if (rc !is XPCOM.NS_OK) {
1061         browser.dispose();
1062         error(rc);
1063     }
1064     if (uriContentListener is null) {
1065         browser.dispose();
1066         error(XPCOM.NS_ERROR_NO_INTERFACE);
1067     }
1068 
1069     rc = webBrowser.SetParentURIContentListener (uriContentListener);
1070     if (rc !is XPCOM.NS_OK) {
1071         browser.dispose ();
1072         error (rc, __FILE__, __LINE__);
1073     }
1074 
1075     mozDelegate.init ();
1076         
1077     int[] folderEvents = [
1078         SWT.Dispose,
1079         SWT.Resize,  
1080         SWT.FocusIn,
1081         SWT.Activate,
1082         SWT.Deactivate,
1083         SWT.Show,
1084         SWT.KeyDown     // needed to make browser traversable
1085     ];
1086     
1087     for (int i = 0; i < folderEvents.length; i++) {
1088         browser.addListener (folderEvents[i], dgListener( &handleFolderEvent ));
1089     }
1090 }
1091 
1092 /*******************************************************************************
1093 
1094     Event Handlers for the Mozilla Class:
1095     
1096     These represent replacements for SWT's anonymous classes as used within
1097     the Mozilla class.  Since D 1.0x anonymous classes do not work equivalently 
1098     to Java's, we replace the anonymous classes with D delegates and templates
1099     (ie dgListener which wrap the delegate in a class).  This circumvents some
1100     nasty, evasive bugs.
1101     
1102     extern(D) becomes a necessary override on these methods because this class 
1103     implements a XPCOM/COM interface resulting in all class methods defaulting
1104     to extern(System). -JJR
1105 
1106  ******************************************************************************/
1107 
1108 extern(D)
1109 private void handleDisposeEvent (Event event, Display display) {
1110     if (BrowserCount > 0) return; /* another display is still active */
1111 
1112     nsIServiceManager serviceManager;
1113 
1114     int rc = XPCOM.NS_GetServiceManager (&serviceManager);
1115     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1116     if (serviceManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1117 
1118     nsIObserverService observerService;
1119     rc = serviceManager.GetServiceByContractID (XPCOM.NS_OBSERVER_CONTRACTID.ptr, &nsIObserverService.IID, cast(void**)&observerService);
1120     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1121     if (observerService is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1122 
1123     rc = observerService.NotifyObservers (null, PROFILE_BEFORE_CHANGE.ptr, SHUTDOWN_PERSIST.toWCharArray().toString16z());
1124     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1125     observerService.Release ();
1126 
1127     if (LocationProvider !is null) {
1128         String prefsLocation = LocationProvider.profilePath ~ AppFileLocProvider.PREFERENCES_FILE;
1129         scope auto pathString = new nsEmbedString (prefsLocation.toWCharArray());
1130         nsILocalFile localFile;
1131         rc = XPCOM.NS_NewLocalFile (cast(nsAString*)pathString, 1, &localFile);
1132         if (rc !is XPCOM.NS_OK) Mozilla.error (rc, __FILE__, __LINE__);
1133         if (localFile is null) Mozilla.error (XPCOM.NS_ERROR_NULL_POINTER);
1134 
1135         nsIFile prefFile;
1136         rc = localFile.QueryInterface (&nsIFile.IID, cast(void**)&prefFile); 
1137         if (rc !is XPCOM.NS_OK) Mozilla.error (rc, __FILE__, __LINE__);
1138         if (prefFile is null) Mozilla.error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1139         localFile.Release ();
1140 
1141         nsIPrefService prefService;
1142         rc = serviceManager.GetServiceByContractID (XPCOM.NS_PREFSERVICE_CONTRACTID.ptr, &nsIPrefService.IID, cast(void**)&prefService);
1143         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1144         if (prefService is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1145 
1146         rc = prefService.SavePrefFile(prefFile);
1147         prefService.Release ();
1148         prefFile.Release ();
1149     }
1150     serviceManager.Release ();
1151 
1152     if (XPCOMWasGlued) {
1153         /*
1154          * XULRunner 1.9 can crash on Windows if XPCOMGlueShutdown is invoked here,
1155          * presumably because one or more of its unloaded symbols are referenced when
1156          * this callback returns.  The workaround is to delay invoking XPCOMGlueShutdown
1157          * so that its symbols are still available once this callback returns.
1158          */
1159          display.asyncExec (new class() Runnable {
1160              public void run () {
1161                  XPCOMInit.XPCOMGlueShutdown ();
1162              }
1163          });
1164          XPCOMWasGlued = XPCOMInitWasGlued = false;
1165     } 
1166 
1167     Initialized = false;
1168 }
1169   
1170         
1171 extern(D)
1172 private void handleFolderEvent (Event event) {
1173             Control control = cast(Control)browser;
1174             switch (event.type) {
1175                 case SWT.Dispose: {
1176                     /* make this handler run after other dispose listeners */
1177                     if (ignoreDispose) {
1178                         ignoreDispose = false;
1179                         break;
1180                     }
1181                     ignoreDispose = true;
1182                     browser.notifyListeners (event.type, event);
1183                     event.type = SWT.NONE;
1184                     onDispose (event.display);
1185                     break;
1186                 }
1187                 case SWT.Resize: onResize (); break;
1188                 case SWT.FocusIn: Activate (); break;
1189                 case SWT.Activate: Activate (); break;
1190                 case SWT.Deactivate: {
1191                     Display display = event.display;
1192                     if (control is display.getFocusControl ()) Deactivate ();
1193                     break;
1194                 }
1195                 case SWT.Show: {
1196                     /*
1197                     * Feature in GTK Mozilla.  Mozilla does not show up when
1198                     * its container (a GTK fixed handle) is made visible
1199                     * after having been hidden.  The workaround is to reset
1200                     * its size after the container has been made visible. 
1201                     */
1202                     Display display = event.display;
1203                     display.asyncExec(new class () Runnable {
1204                         public void run() {
1205                             if (browser.isDisposed ()) return;
1206                             onResize ();
1207                         }
1208                     });
1209                     break;
1210                 }
1211                 default: break;
1212             }
1213         }
1214 
1215 /*******************************************************************************
1216 
1217 *******************************************************************************/
1218     
1219 extern(D)
1220 public bool back () {
1221     if (awaitingNavigate) return false;
1222 
1223     //ptrdiff_t[] result = new ptrdiff_t[1];
1224     nsIWebNavigation webNavigation;
1225     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1226     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1227     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1228     
1229     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);          
1230     rc = webNavigation.GoBack ();   
1231     webNavigation.Release ();
1232     return rc is XPCOM.NS_OK;
1233 }
1234 
1235 extern(D)
1236 public bool execute (String script) {
1237     if (awaitingNavigate) return false;
1238 
1239     String url = PREFIX_JAVASCRIPT ~ script ~ ";void(0);";  //$NON-NLS-1$
1240     //ptrdiff_t[] result = new ptrdiff_t[1];
1241     nsIWebNavigation webNavigation;
1242     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1243     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1244     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1245 
1246     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
1247     //char[] arg = url.toCharArray (); 
1248     //char[] c = new char[arg.length+1];
1249     //System.arraycopy (arg, 0, c, 0, arg.length);
1250     rc = webNavigation.LoadURI (url.toWCharArray().toString16z(), nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
1251     webNavigation.Release ();
1252     return rc is XPCOM.NS_OK;
1253 }
1254 
1255 extern(D)
1256 static Browser findBrowser (void* handle) {
1257     return MozillaDelegate.findBrowser (cast(GtkWidget*)handle);
1258 }
1259 
1260 extern(D)
1261 public bool forward () {
1262     if (awaitingNavigate) return false;
1263 
1264     //ptrdiff_t[] result = new ptrdiff_t[1];
1265     nsIWebNavigation webNavigation;
1266     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1267     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1268     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1269     
1270     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
1271     rc = webNavigation.GoForward ();
1272     webNavigation.Release ();
1273 
1274     return rc is XPCOM.NS_OK;
1275 }
1276 
1277 extern(D)
1278 public String getText () {
1279     if (awaitingNavigate) return ""; //$NON-NLS-1$
1280 
1281     //ptrdiff_t[] result = new ptrdiff_t[1];
1282     nsIDOMWindow window;
1283     int rc = webBrowser.GetContentDOMWindow (&window);
1284     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1285     if (window is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1286 
1287     //nsIDOMWindow window = new nsIDOMWindow (result[0]);
1288     //result[0] = 0;
1289     nsIDOMDocument document;
1290     rc = window.GetDocument (&document);
1291     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1292     if (document is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1293     window.Release ();
1294 
1295     //ptrdiff_t document = result[0];
1296     //result[0] = 0;
1297     nsIComponentManager componentManager;
1298     rc = XPCOM.NS_GetComponentManager (&componentManager);
1299     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1300     if (componentManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1301 
1302     //nsIComponentManager componentManager = new nsIComponentManager (result[0]);
1303     //result[0] = 0;
1304     //byte[] contractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_DOMSERIALIZER_CONTRACTID, true);
1305     String chars = null;
1306     nsIDOMSerializer_1_7 serializer_1_7;
1307     rc = componentManager.CreateInstanceByContractID (XPCOM.NS_DOMSERIALIZER_CONTRACTID.ptr, null, &nsIDOMSerializer_1_7.IID, cast(void**)&serializer_1_7);
1308     if (rc is XPCOM.NS_OK) {    /* mozilla >= 1.7 */
1309         if (serializer_1_7 is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1310 
1311         //nsIDOMSerializer_1_7 serializer = new nsIDOMSerializer_1_7 (result[0]);
1312         //result[0] = 0;
1313         scope auto string = new nsEmbedString;
1314         rc = serializer_1_7.SerializeToString (cast(nsIDOMNode)document, cast(nsAString*) string);
1315         serializer_1_7.Release ();
1316 
1317         //int length = XPCOM.nsEmbedString_Length (string);
1318         //ptrdiff_t buffer = XPCOM.nsEmbedString_get (string);
1319         //chars = new char[length];
1320         //XPCOM.memmove (chars, buffer, length * 2);
1321         //XPCOM.nsEmbedString_delete (string);
1322         chars = string.toString();
1323     } else {    /* mozilla < 1.7 */
1324         nsIDOMSerializer serializer;
1325         rc = componentManager.CreateInstanceByContractID (XPCOM.NS_DOMSERIALIZER_CONTRACTID.ptr, null, &nsIDOMSerializer.IID, cast(void**)&serializer);
1326         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1327         if (serializer is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1328         // TODO: Lookup SerializeToString contract. Find out if the string must provide it's own memory to the method. -JJR
1329         PRUnichar* string;
1330         //nsIDOMSerializer serializer = new nsIDOMSerializer (result[0]);
1331         //result[0] = 0;
1332         rc = serializer.SerializeToString (cast(nsIDOMNode)document, &string );
1333         serializer.Release ();
1334 
1335         //int length = XPCOM.strlen_PRUnichar (string);
1336         //chars = new char[length];
1337         //XPCOM.memmove (chars, result[0], length * 2);
1338         chars = String_valueOf(fromString16z(string));
1339     }
1340 
1341     componentManager.Release ();
1342     document.Release ();
1343     return chars._idup();
1344 }
1345 
1346 extern(D)
1347 public String getUrl () {
1348     if (awaitingNavigate) return ""; //$NON-NLS-1$
1349 
1350     //ptrdiff_t[] result = new ptrdiff_t[1];
1351     nsIWebNavigation webNavigation;
1352     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1353     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1354     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1355 
1356     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
1357     nsIURI aCurrentURI;
1358     rc = webNavigation.GetCurrentURI (&aCurrentURI);
1359     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1360     webNavigation.Release ();
1361 
1362     String location = null;
1363     if (aCurrentURI !is null) {
1364         //nsIURI uri = new nsIURI (aCurrentURI[0]);
1365         scope auto aSpec = new nsEmbedCString;
1366         rc = aCurrentURI.GetSpec (cast(nsACString*)aSpec);
1367         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1368         //int length = XPCOM.nsEmbedCString_Length (aSpec);
1369         //ptrdiff_t buffer = XPCOM.nsEmbedCString_get (aSpec);
1370         location = aSpec.toString;
1371         //XPCOM.memmove (dest, buffer, length);
1372         //XPCOM.nsEmbedCString_delete (aSpec);
1373         aCurrentURI.Release ();
1374     }
1375     if (location is null) return ""; //$NON-NLS-1$
1376 
1377     /*
1378      * If the URI indicates that the page is being rendered from memory
1379      * (via setText()) then set it to about:blank to be consistent with IE.
1380      */
1381     if (location.equals (URI_FROMMEMORY)) location = ABOUT_BLANK;
1382     return location;
1383 }
1384 
1385 extern(D)
1386 public Object getWebBrowser () {
1387     if ((browser.getStyle () & SWT.MOZILLA) is 0) return null;
1388     if (webBrowserObject !is null) return webBrowserObject;
1389     implMissing(__FILE__,__LINE__);
1390 /+
1391     try {
1392         // TODO: this references the JavaXPCOM browser... not sure what needs to be done here,
1393         // but I don't think this method is necessary.
1394         Class clazz = Class.forName ("org.mozilla.xpcom.Mozilla"); //$NON-NLS-1$
1395         Method method = clazz.getMethod ("getInstance", new Class[0]); //$NON-NLS-1$
1396         Object mozilla = method.invoke (null, new Object[0]);
1397         method = clazz.getMethod ("wrapXPCOMObject", new Class[] {Long.TYPE, String.class}); //$NON-NLS-1$
1398         webBrowserObject = webBrowser.getAddress ()), nsIWebBrowser.NS_IWEBBROWSER_IID_STR});
1399         /*
1400          * The following AddRef() is needed to offset the automatic Release() that
1401          * will be performed by JavaXPCOM when webBrowserObject is finalized.
1402          */
1403         webBrowser.AddRef ();
1404         return webBrowserObject;
1405    } catch (ClassNotFoundException e) {
1406    } catch (NoSuchMethodException e) {
1407    } catch (IllegalArgumentException e) {
1408    } catch (IllegalAccessException e) {
1409    } catch (InvocationTargetException e) {
1410    }
1411 +/
1412    return null;
1413 }
1414 
1415 extern(D)
1416 public bool isBackEnabled () {
1417     if (awaitingNavigate) return false;
1418 
1419     //ptrdiff_t[] result = new ptrdiff_t[1];
1420     nsIWebNavigation webNavigation;
1421     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1422     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1423     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1424     
1425     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
1426     PRBool aCanGoBack; /* PRBool */
1427     rc = webNavigation.GetCanGoBack (&aCanGoBack);   
1428     webNavigation.Release ();
1429     return aCanGoBack !is 0;
1430 }
1431 
1432 extern(D)
1433 public bool isForwardEnabled () {
1434     if (awaitingNavigate) return false;
1435 
1436     //ptrdiff_t[] result = new ptrdiff_t[1];
1437     nsIWebNavigation webNavigation;
1438     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1439     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1440     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1441     
1442     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);
1443     PRBool aCanGoForward; /* PRBool */
1444     rc = webNavigation.GetCanGoForward (&aCanGoForward);
1445     webNavigation.Release ();
1446     return aCanGoForward !is 0;
1447 }
1448 
1449 extern(D)
1450 static void error (int code ) {
1451     error ( code, "NOT GIVEN", 0 );
1452 }
1453 
1454 extern(D)
1455 static void error (int code, String file, int line) {
1456     getDwtLogger().info( __FILE__, __LINE__,  "File: {}  Line: {}", file, line);
1457     throw new SWTError ("XPCOM error " ~ Integer.toString(code)); //$NON-NLS-1$
1458 }
1459 
1460 extern(D)
1461 void onDispose (Display display) {
1462     int rc = webBrowser.RemoveWebBrowserListener (cast(nsIWeakReference)this, &nsIWebProgressListener.IID);
1463     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1464 
1465     rc = webBrowser.SetParentURIContentListener (null);
1466     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1467     
1468     unhookDOMListeners ();
1469     if (listener !is null) {
1470         int[] folderEvents = [
1471             SWT.Dispose,
1472             SWT.Resize,  
1473             SWT.FocusIn,
1474             SWT.Activate,
1475             SWT.Deactivate,
1476             SWT.Show,
1477             SWT.KeyDown,
1478         ];
1479         for (int i = 0; i < folderEvents.length; i++) {
1480             browser.removeListener (folderEvents[i], listener);
1481         }
1482         listener = null;
1483     }
1484 
1485     //ptrdiff_t[] result = new ptrdiff_t[1];
1486     nsIBaseWindow baseWindow;
1487     rc = webBrowser.QueryInterface (&nsIBaseWindow.IID, cast(void**)&baseWindow);
1488     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1489     if (baseWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1490 
1491     //nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
1492     rc = baseWindow.Destroy ();
1493     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1494     baseWindow.Release ();
1495 
1496     Release ();
1497     webBrowser.Release ();
1498     webBrowser = null;
1499     webBrowserObject = null;
1500 
1501     if (tip !is null && !tip.isDisposed ()) tip.dispose ();
1502     tip = null;
1503     location = size = null;
1504 
1505     //Enumeration elements = unhookedDOMWindows.elements ();
1506     foreach (win ; unhookedDOMWindows) {
1507         //LONG ptrObject = (LONG)elements.nextElement ();
1508         win.Release ();
1509     }
1510     unhookedDOMWindows = null;
1511 
1512     mozDelegate.onDispose (embedHandle);
1513     mozDelegate = null;
1514 
1515     embedHandle = null;
1516     BrowserCount--;
1517 }
1518 
1519 extern(D)
1520 void Activate () {
1521     //ptrdiff_t[] result = new ptrdiff_t[1];
1522     nsIWebBrowserFocus webBrowserFocus;
1523     int rc = webBrowser.QueryInterface (&nsIWebBrowserFocus.IID, cast(void**)&webBrowserFocus);
1524     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1525     if (webBrowserFocus is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1526     
1527     //nsIWebBrowserFocus webBrowserFocus = new nsIWebBrowserFocus (result[0]);
1528     rc = webBrowserFocus.Activate ();
1529     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1530     webBrowserFocus.Release ();
1531 }
1532 
1533 extern(D)
1534 void Deactivate () {
1535     //ptrdiff_t[] result = new ptrdiff_t[1];
1536     nsIWebBrowserFocus webBrowserFocus;
1537     int rc = webBrowser.QueryInterface (&nsIWebBrowserFocus.IID, cast(void**)&webBrowserFocus);
1538     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1539     if (webBrowserFocus is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1540     
1541     //nsIWebBrowserFocus webBrowserFocus = new nsIWebBrowserFocus (result[0]);
1542     rc = webBrowserFocus.Deactivate ();
1543     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1544     webBrowserFocus.Release ();
1545 }
1546 
1547 extern(D)
1548 void onResize () {
1549     Rectangle rect = browser.getClientArea ();
1550     int width = Math.max (1, rect.width);
1551     int height = Math.max (1, rect.height);
1552 
1553     //ptrdiff_t[] result = new ptrdiff_t[1];
1554     nsIBaseWindow baseWindow;
1555     int rc = webBrowser.QueryInterface (&nsIBaseWindow.IID, cast(void**)&baseWindow);
1556     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1557     if (baseWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1558 
1559     mozDelegate.setSize (embedHandle, width, height);
1560     //nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
1561     rc = baseWindow.SetPositionAndSize (0, 0, width, height, 1);
1562     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1563     baseWindow.Release ();
1564 }
1565 
1566 extern(D)
1567 public void refresh () {
1568     if (awaitingNavigate) return;
1569 
1570     //ptrdiff_t[] result = new ptrdiff_t[1];
1571     nsIWebNavigation webNavigation;
1572     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1573     if (rc !is XPCOM.NS_OK) error(rc);
1574     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1575     
1576     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);          
1577     rc = webNavigation.Reload (nsIWebNavigation.LOAD_FLAGS_NONE);
1578     webNavigation.Release ();
1579     if (rc is XPCOM.NS_OK) return;
1580     /*
1581     * Feature in Mozilla.  Reload returns an error code NS_ERROR_INVALID_POINTER
1582     * when it is called immediately after a request to load a new document using
1583     * LoadURI.  The workaround is to ignore this error code.
1584     *
1585     * Feature in Mozilla.  Attempting to reload a file that no longer exists
1586     * returns an error code of NS_ERROR_FILE_NOT_FOUND.  This is equivalent to
1587     * attempting to load a non-existent local url, which is not a Browser error,
1588     * so this error code should be ignored. 
1589     */
1590     if (rc !is XPCOM.NS_ERROR_INVALID_POINTER && rc !is XPCOM.NS_ERROR_FILE_NOT_FOUND) error (rc, __FILE__, __LINE__);
1591 }
1592 
1593 extern(D)
1594 public bool setText (String html) {
1595     /*
1596     *  Feature in Mozilla.  The focus memory of Mozilla must be 
1597     *  properly managed through the nsIWebBrowserFocus interface.
1598     *  In particular, nsIWebBrowserFocus.deactivate must be called
1599     *  when the focus moves from the browser (or one of its children
1600     *  managed by Mozilla to another widget.  We currently do not
1601     *  get notified when a widget takes focus away from the Browser.
1602     *  As a result, deactivate is not properly called. This causes
1603     *  Mozilla to retake focus the next time a document is loaded.
1604     *  This breaks the case where the HTML loaded in the Browser 
1605     *  varies while the user enters characters in a text widget. The text
1606     *  widget loses focus every time new content is loaded.
1607     *  The current workaround is to call deactivate everytime if 
1608     *  the browser currently does not have focus. A better workaround
1609     *  would be to have a way to call deactivate when the Browser
1610     *  or one of its children loses focus.
1611     */
1612     if (browser !is browser.getDisplay().getFocusControl ()) {
1613         Deactivate ();
1614     }
1615     /* convert the String containing HTML to an array of bytes with UTF-8 data */
1616     /+
1617     byte[] data = null;
1618     try {
1619         data = html.getBytes ("UTF-8"); //$NON-NLS-1$
1620     } catch (UnsupportedEncodingException e) {
1621         return false;
1622     }
1623     +/
1624     awaitingNavigate = false;
1625 
1626     //byte[] contentTypeBuffer = MozillaDelegate.wcsToMbcs (null, "text/html", true); // $NON-NLS-1$
1627     scope auto aContentType = new nsEmbedCString ("text/html");
1628     //byte[] contentCharsetBuffer = MozillaDelegate.wcsToMbcs (null, "UTF-8", true);  //$NON-NLS-1$
1629     scope auto aContentCharset = new nsEmbedCString ("UTF-8");
1630 
1631     //ptrdiff_t[] result = new ptrdiff_t[1];
1632     nsIServiceManager serviceManager;
1633     int rc = XPCOM.NS_GetServiceManager (&serviceManager);
1634     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1635     if (serviceManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1636 
1637     //nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
1638     //result[0] = 0;
1639     nsIIOService ioService;
1640     rc = serviceManager.GetService (&XPCOM.NS_IOSERVICE_CID, &nsIIOService.IID, cast(void**)&ioService);
1641     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1642     if (ioService is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1643     serviceManager.Release ();
1644 
1645     //nsIIOService ioService = new nsIIOService (result[0]);
1646     //result[0] = 0;
1647     /*
1648     * Note.  Mozilla ignores LINK tags used to load CSS stylesheets
1649     * when the URI protocol for the nsInputStreamChannel
1650     * is about:blank.  The fix is to specify the file protocol.
1651     */
1652     //byte[] aString = MozillaDelegate.wcsToMbcs (null, URI_FROMMEMORY, false);
1653     scope auto aSpec = new nsEmbedCString(URI_FROMMEMORY);
1654     nsIURI uri;
1655     rc = ioService.NewURI (cast(nsACString*)aSpec, null, null, &uri);
1656     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1657     if (uri is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
1658     //XPCOM.nsEmbedCString_delete (aSpec);
1659     ioService.Release ();
1660 
1661     //nsIURI uri = new nsIURI (result[0]);
1662     //result[0] = 0;
1663     nsIInterfaceRequestor interfaceRequestor;
1664     rc = webBrowser.QueryInterface (&nsIInterfaceRequestor.IID, cast(void**)&interfaceRequestor);
1665     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1666     if (interfaceRequestor is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1667     //nsIInterfaceRequestor interfaceRequestor = new nsIInterfaceRequestor (result[0]);
1668     //result[0] = 0;
1669 
1670     /*
1671     * Feature in Mozilla. LoadStream invokes the nsIInputStream argument
1672     * through a different thread.  The callback mechanism must attach 
1673     * a non java thread to the JVM otherwise the nsIInputStream Read and
1674     * Close methods never get called.
1675     */
1676     
1677     // Using fully qualified name for disambiguation with java.io.InputStream -JJR
1678     auto inputStream = new org.eclipse.swt.browser.InputStream.InputStream (cast(byte[])html);
1679     inputStream.AddRef ();
1680 
1681     nsIDocShell_1_9 docShell_1_9;
1682     rc = interfaceRequestor.GetInterface (&nsIDocShell_1_9.IID, cast(void**)&docShell_1_9);
1683     if (rc is XPCOM.NS_OK) {
1684         if (docShell_1_9 is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1685         //nsIDocShell_1_9 docShell = new nsIDocShell_1_9 (result[0]);
1686         rc = docShell_1_9.LoadStream (inputStream, uri, cast(nsACString*)aContentType,  cast(nsACString*)aContentCharset, null);
1687         docShell_1_9.Release ();
1688     } else {
1689         //result[0] = 0;
1690         nsIDocShell_1_8 docShell_1_8;
1691         rc = interfaceRequestor.GetInterface (&nsIDocShell_1_8.IID, cast(void**)&docShell_1_8);
1692         if (rc is XPCOM.NS_OK) {    
1693             if (docShell_1_8 is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1694             //nsIDocShell_1_8 docShell = new nsIDocShell_1_8 (result[0]);
1695             rc = docShell_1_8.LoadStream (inputStream, uri, cast(nsACString*)aContentType,  cast(nsACString*)aContentCharset, null);
1696             docShell_1_8.Release ();
1697         } else {
1698             //result[0] = 0;
1699             nsIDocShell docShell;
1700             rc = interfaceRequestor.GetInterface (&nsIDocShell.IID, cast(void**)&docShell);
1701             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1702             if (docShell is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1703             //nsIDocShell docShell = new nsIDocShell (result[0]);
1704             rc = docShell.LoadStream (inputStream, uri, cast(nsACString*) aContentType,  cast(nsACString*)aContentCharset, null);
1705             docShell.Release ();
1706         }
1707     }
1708     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1709     //result[0] = 0;
1710 
1711     inputStream.Release ();
1712     interfaceRequestor.Release ();
1713     uri.Release ();
1714     //XPCOM.nsEmbedCString_delete (aContentCharset);
1715     //XPCOM.nsEmbedCString_delete (aContentType);
1716     return true;
1717 }
1718 
1719 extern(D)
1720 public bool setUrl (String url) {
1721     awaitingNavigate = false;
1722 
1723     nsIWebNavigation webNavigation;
1724     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1725     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1726     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1727 
1728     rc = webNavigation.LoadURI (url.toWCharArray().toString16z(), nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
1729     webNavigation.Release ();
1730     return rc is XPCOM.NS_OK;
1731 }
1732 
1733 extern(D)
1734 public void stop () {
1735     if (awaitingNavigate) return;
1736 
1737     nsIWebNavigation webNavigation;
1738     //ptrdiff_t[] result = new ptrdiff_t[1];
1739     int rc = webBrowser.QueryInterface (&nsIWebNavigation.IID, cast(void**)&webNavigation);
1740     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1741     if (webNavigation is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1742     
1743     //nsIWebNavigation webNavigation = new nsIWebNavigation (result[0]);      
1744     rc = webNavigation.Stop (nsIWebNavigation.STOP_ALL);
1745     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1746     webNavigation.Release ();
1747 }
1748 
1749 extern(D)
1750 void hookDOMListeners (nsIDOMEventTarget target, bool isTop) {
1751     scope auto string = new nsEmbedString (XPCOM.DOMEVENT_FOCUS.toWCharArray());
1752     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1753     //string.dispose ();
1754     string = new nsEmbedString (XPCOM.DOMEVENT_UNLOAD.toWCharArray());
1755     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1756     //string.dispose ();
1757     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDOWN.toWCharArray());
1758     target.AddEventListener (cast(nsAString*)string,cast(nsIDOMEventListener)this, 0);
1759     //string.dispose ();
1760     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEUP.toWCharArray());
1761     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1762     //string.dispose ();
1763     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEMOVE.toWCharArray());
1764     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1765     //string.dispose ();
1766     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEWHEEL.toWCharArray());
1767     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1768     //string.dispose ();
1769     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDRAG.toWCharArray());
1770     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1771     //string.dispose ();
1772 
1773     /*
1774     * Only hook mouseover and mouseout if the target is a top-level frame, so that mouse moves
1775     * between frames will not generate events.
1776     */
1777     if (isTop && mozDelegate.hookEnterExit ()) {
1778         string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOVER.toWCharArray());
1779         target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1780         //string.dispose ();
1781         string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOUT.toWCharArray());
1782         target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1783         //string.dispose ();
1784     }
1785 
1786     string = new nsEmbedString (XPCOM.DOMEVENT_KEYDOWN.toWCharArray());
1787     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1788     //string.dispose ();
1789     string = new nsEmbedString (XPCOM.DOMEVENT_KEYPRESS.toWCharArray());
1790     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1791     //string.dispose ();
1792     string = new nsEmbedString (XPCOM.DOMEVENT_KEYUP.toWCharArray());
1793     target.AddEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1794     //string.dispose ();
1795 }
1796 
1797 extern(D)
1798 void unhookDOMListeners () {
1799     //ptrdiff_t[] result = new ptrdiff_t[1];
1800     nsIDOMWindow window;
1801     int rc = webBrowser.GetContentDOMWindow (&window);
1802     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1803     if (window is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1804 
1805     //nsIDOMWindow window = new nsIDOMWindow (result[0]);
1806     //result[0] = 0;
1807     nsIDOMEventTarget target;
1808     rc = window.QueryInterface (&nsIDOMEventTarget.IID, cast(void**)&target);
1809     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1810     if (target is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1811 
1812     //nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
1813     //result[0] = 0;
1814     unhookDOMListeners (target);
1815     target.Release ();
1816 
1817     /* Listeners must be unhooked in pages contained in frames */
1818     nsIDOMWindowCollection frames;
1819     rc = window.GetFrames (&frames);
1820     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1821     if (frames is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1822     //nsIDOMWindowCollection frames = new nsIDOMWindowCollection (result[0]);
1823     //result[0] = 0;
1824     PRUint32 count;
1825     rc = frames.GetLength (&count); /* PRUint32 */
1826     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1827     //int count = frameCount[0];
1828 
1829     if (count > 0) {
1830         nsIDOMWindow frame;
1831         for (int i = 0; i < count; i++) {
1832             rc = frames.Item (i, &frame);
1833             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1834             if (frame is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1835 
1836             //nsIDOMWindow frame = new nsIDOMWindow (result[0]);
1837             //result[0] = 0;
1838             rc = frame.QueryInterface (&nsIDOMEventTarget.IID, cast(void**)&target);
1839             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1840             if (target is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1841 
1842             //target = new nsIDOMEventTarget (result[0]);
1843             //result[0] = 0;
1844             unhookDOMListeners (target);
1845             target.Release ();
1846             frame.Release ();
1847         }
1848     }
1849     frames.Release ();
1850     window.Release ();
1851 }
1852 
1853 extern(D)
1854 void unhookDOMListeners (nsIDOMEventTarget target) {
1855     scope auto string = new nsEmbedString (XPCOM.DOMEVENT_FOCUS.toWCharArray());
1856     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1857     //string.dispose ();
1858     string = new nsEmbedString (XPCOM.DOMEVENT_UNLOAD.toWCharArray());
1859     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1860     //string.dispose ();
1861     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDOWN.toWCharArray());
1862     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1863     //string.dispose ();
1864     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEUP.toWCharArray());
1865     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1866     //string.dispose ();
1867     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEMOVE.toWCharArray());
1868     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1869     //string.dispose ();
1870     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEWHEEL.toWCharArray());
1871     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1872     //string.dispose ();
1873     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEDRAG.toWCharArray());
1874     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1875     //string.dispose ();
1876     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOVER.toWCharArray());
1877     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1878     //string.dispose ();
1879     string = new nsEmbedString (XPCOM.DOMEVENT_MOUSEOUT.toWCharArray());
1880     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1881     //string.dispose ();
1882     string = new nsEmbedString (XPCOM.DOMEVENT_KEYDOWN.toWCharArray());
1883     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1884     //string.dispose ();
1885     string = new nsEmbedString (XPCOM.DOMEVENT_KEYPRESS.toWCharArray());
1886     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1887     //string.dispose ();
1888     string = new nsEmbedString (XPCOM.DOMEVENT_KEYUP.toWCharArray());
1889     target.RemoveEventListener (cast(nsAString*)string, cast(nsIDOMEventListener)this, 0);
1890     //string.dispose ();
1891 }
1892 
1893 /* nsISupports */
1894 
1895 extern(System)
1896 nsresult QueryInterface (in nsID* riid, void** ppvObject) {
1897     if (riid is null || ppvObject is null) return XPCOM.NS_ERROR_NO_INTERFACE;
1898 
1899     if (*riid == nsISupports.IID) {
1900         *ppvObject = cast(void*)cast(nsISupports)this;
1901         AddRef ();
1902         return XPCOM.NS_OK;
1903     }
1904     if (*riid == nsIWeakReference.IID) {
1905         *ppvObject = cast(void*)cast(nsIWeakReference)this;
1906         AddRef ();
1907         return XPCOM.NS_OK;
1908     }
1909     if (*riid == nsIWebProgressListener.IID) {
1910         *ppvObject = cast(void*)cast(nsIWebProgressListener)this;
1911         AddRef ();
1912         return XPCOM.NS_OK;
1913     }
1914     if (*riid == nsIWebBrowserChrome.IID) {
1915         *ppvObject = cast(void*)cast(nsIWebBrowserChrome)this;
1916         AddRef ();
1917         return XPCOM.NS_OK;
1918     }
1919     if (*riid == nsIWebBrowserChromeFocus.IID) {
1920         *ppvObject = cast(void*)cast(nsIWebBrowserChromeFocus)this;
1921         AddRef ();
1922         return XPCOM.NS_OK;
1923     }
1924     if (*riid == nsIEmbeddingSiteWindow.IID) {
1925         *ppvObject = cast(void*)cast(nsIEmbeddingSiteWindow)this;
1926         AddRef ();
1927         return XPCOM.NS_OK;
1928     }
1929     if (*riid == nsIInterfaceRequestor.IID) {
1930         *ppvObject = cast(void*)cast(nsIInterfaceRequestor)this;
1931         AddRef ();
1932         return XPCOM.NS_OK;
1933     }
1934     if (*riid == nsISupportsWeakReference.IID) {
1935         *ppvObject = cast(void*)cast(nsISupportsWeakReference)this;
1936         AddRef ();
1937         return XPCOM.NS_OK;
1938     }
1939     if (*riid == nsIContextMenuListener.IID) {
1940         *ppvObject = cast(void*)cast(nsIContextMenuListener)this;
1941         AddRef ();
1942         return XPCOM.NS_OK;
1943     }
1944     if (*riid == nsIURIContentListener.IID) {
1945         *ppvObject = cast(void*)cast(nsIURIContentListener)this;
1946         AddRef ();
1947         return XPCOM.NS_OK;
1948     }
1949     if (*riid == nsITooltipListener.IID) {
1950         *ppvObject = cast(void*)cast(nsITooltipListener)this;
1951         AddRef ();
1952         return XPCOM.NS_OK;
1953     }
1954     *ppvObject = null;
1955     return XPCOM.NS_ERROR_NO_INTERFACE;
1956 }
1957 
1958 extern(System)
1959 nsrefcnt AddRef () {
1960     refCount++;
1961     return refCount;
1962 }
1963 
1964 extern(System)
1965 nsrefcnt Release () {
1966     refCount--;
1967     if (refCount is 0) return 0;
1968     return refCount;
1969 }
1970 
1971 /* nsIWeakReference */  
1972 
1973 extern(System)
1974 nsresult QueryReferent (nsID* riid, void** ppvObject) {
1975     return QueryInterface (riid, ppvObject);
1976 }
1977 
1978 /* nsIInterfaceRequestor */
1979 
1980 extern(System)
1981 nsresult GetInterface ( in nsID* riid, void** ppvObject) {
1982     if (riid is null || ppvObject is null) return XPCOM.NS_ERROR_NO_INTERFACE;
1983     //nsID guid = new nsID ();
1984     //XPCOM.memmove (guid, riid, nsID.sizeof);
1985     if (*riid == nsIDOMWindow.IID) {
1986         nsIDOMWindow aContentDOMWindow;
1987         //ptrdiff_t[] aContentDOMWindow = new ptrdiff_t[1];
1988         int rc = webBrowser.GetContentDOMWindow (&aContentDOMWindow);
1989         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
1990         if (aContentDOMWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
1991         *ppvObject = cast(void*)aContentDOMWindow;
1992         //XPCOM.memmove (ppvObject, aContentDOMWindow, C.PTR_SIZEOF);
1993         return rc;
1994     }
1995     return QueryInterface (riid, ppvObject);
1996 }
1997 
1998 extern(System)
1999 nsresult GetWeakReference (nsIWeakReference* ppvObject) {
2000     *ppvObject = cast(nsIWeakReference)this;
2001     //XPCOM.memmove (ppvObject, new ptrdiff_t[] {weakReference.getAddress ()}, C.PTR_SIZEOF);
2002     AddRef ();
2003     return XPCOM.NS_OK;
2004 }
2005 
2006 /* nsIWebProgressListener */
2007 
2008 extern(System)
2009 nsresult OnStateChange (nsIWebProgress aWebProgress, nsIRequest aRequest, PRUint32 aStateFlags, nsresult aStatus) {
2010     if ((aStateFlags & nsIWebProgressListener.STATE_IS_DOCUMENT) is 0) return XPCOM.NS_OK;
2011     if ((aStateFlags & nsIWebProgressListener.STATE_START) !is 0) {
2012         if (request is null) request = aRequest;
2013 
2014         if (!awaitingNavigate) {
2015             /*
2016              * Add the page's nsIDOMWindow to the collection of windows that will
2017              * have DOM listeners added to them later on in the page loading
2018              * process.  These listeners cannot be added yet because the
2019              * nsIDOMWindow is not ready to take them at this stage.
2020              */
2021             //ptrdiff_t[] result = new ptrdiff_t[1];
2022             nsIDOMWindow window;
2023             //nsIWebProgress progress = new nsIWebProgress (aWebProgress);
2024             int rc = aWebProgress.GetDOMWindow (&window);
2025             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2026             if (window is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2027             unhookedDOMWindows ~= window;
2028         }
2029     } else if ((aStateFlags & nsIWebProgressListener.STATE_REDIRECTING) !is 0) {
2030         if (request is aRequest) request = null;
2031     } else if ((aStateFlags & nsIWebProgressListener.STATE_STOP) !is 0) {
2032         /*
2033         * If this page's nsIDOMWindow handle is still in unhookedDOMWindows then
2034         * add its DOM listeners now.  It's possible for this to happen since
2035         * there is no guarantee that a STATE_TRANSFERRING state change will be
2036         * received for every window in a page, which is when these listeners
2037         * are typically added.
2038         */
2039         //ptrdiff_t[] result = new ptrdiff_t[1];
2040         //nsIWebProgress progress = new nsIWebProgress (aWebProgress);
2041         nsIDOMWindow domWindow;
2042         int rc = aWebProgress.GetDOMWindow (&domWindow);
2043         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2044         if (domWindow is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2045         //nsIDOMWindow domWindow = new nsIDOMWindow (result[0]);
2046 
2047         //LONG ptrObject = new LONG (result[0]);
2048         //result[0] = 0;
2049         int index = unhookedDOMWindows.arrayIndexOf (domWindow);
2050         if (index !is -1) {
2051             nsIDOMWindow contentWindow;
2052             rc = webBrowser.GetContentDOMWindow (&contentWindow);
2053             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2054             if (contentWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2055             bool isTop = contentWindow is domWindow;
2056             contentWindow.Release ();
2057             //result[0] = 0;
2058             nsIDOMEventTarget target;
2059             rc = domWindow.QueryInterface (&nsIDOMEventTarget.IID, cast(void**)&target);
2060             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2061             if (target is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2062 
2063             //nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
2064             //result[0] = 0;
2065             hookDOMListeners (target, isTop);
2066             target.Release ();
2067 
2068             /*
2069             * Remove and unreference the nsIDOMWindow from the collection of windows
2070             * that are waiting to have DOM listeners hooked on them. 
2071             */
2072             unhookedDOMWindows = unhookedDOMWindows.arrayIndexRemove (index);
2073             domWindow.Release ();
2074         }
2075         domWindow.Release ();
2076 
2077         /*
2078         * Feature in Mozilla.  When a request is redirected (STATE_REDIRECTING),
2079         * it never reaches the state STATE_STOP and it is replaced with a new request.
2080         * The new request is received when it is in the state STATE_STOP.
2081         * To handle this case,  the variable request is set to 0 when the corresponding
2082         * request is redirected. The following request received with the state STATE_STOP
2083         * - the new request resulting from the redirection - is used to send
2084         * the ProgressListener.completed event.
2085         */
2086         if (request is aRequest || request is null) {
2087             request = null;
2088             if (!awaitingNavigate) {
2089                 StatusTextEvent event = new StatusTextEvent (browser);
2090                 event.display = browser.getDisplay ();
2091                 event.widget = browser;
2092                 event.text = ""; //$NON-NLS-1$
2093                 for (int i = 0; i < statusTextListeners.length; i++) {
2094                     statusTextListeners[i].changed (event);
2095                 }
2096                 ProgressEvent event2 = new ProgressEvent (browser);
2097                 event2.display = browser.getDisplay ();
2098                 event2.widget = browser;
2099                 for (int i = 0; i < progressListeners.length; i++) {
2100                     progressListeners[i].completed (event2);
2101                 }
2102             }
2103         }
2104     } else if ((aStateFlags & nsIWebProgressListener.STATE_TRANSFERRING) !is 0) {
2105         /*
2106         * Hook DOM listeners to the page's nsIDOMWindow here because this is
2107         * the earliest opportunity to do so.    
2108         */
2109         //ptrdiff_t[] result = new ptrdiff_t[1];
2110        // nsIWebProgress progress = new nsIWebProgress (aWebProgress);
2111         nsIDOMWindow domWindow;
2112         int rc = aWebProgress.GetDOMWindow (&domWindow);
2113         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2114         if (domWindow is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2115         //nsIDOMWindow domWindow = new nsIDOMWindow (result[0]);
2116 
2117         //LONG ptrObject = new LONG (result[0]);
2118         //result[0] = 0;
2119         int index = unhookedDOMWindows.arrayIndexOf ( domWindow);
2120         if (index !is -1) {
2121             nsIDOMWindow contentWindow;
2122             rc = webBrowser.GetContentDOMWindow (&contentWindow);
2123             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2124             if (contentWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2125             bool isTop = contentWindow is domWindow;
2126             contentWindow.Release ();
2127             //result[0] = 0;
2128             nsIDOMEventTarget target;
2129             rc = domWindow.QueryInterface (&nsIDOMEventTarget.IID, cast(void**)&target);
2130             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2131             if (target is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2132 
2133             //nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
2134             //result[0] = 0;
2135             hookDOMListeners (target, isTop);
2136             target.Release ();
2137 
2138             /*
2139             * Remove and unreference the nsIDOMWindow from the collection of windows
2140             * that are waiting to have DOM listeners hooked on them. 
2141             */
2142             unhookedDOMWindows = unhookedDOMWindows.arrayIndexRemove(index);
2143             domWindow.Release ();
2144         }
2145         domWindow.Release ();
2146     }
2147     return XPCOM.NS_OK;
2148 }
2149 
2150 extern(System)
2151 nsresult OnProgressChange (nsIWebProgress aWebProgress, nsIRequest aRequest, PRInt32 aCurSelfProgress, PRInt32 aMaxSelfProgress, PRInt32 aCurTotalProgress, PRInt32 aMaxTotalProgress) {
2152     if (awaitingNavigate || super.progressListeners.length is 0) return XPCOM.NS_OK;
2153     ProgressEvent event = new ProgressEvent (browser);
2154     event.display = browser.getDisplay ();
2155     event.widget = browser;
2156     event.current = aCurTotalProgress;
2157     event.total = aMaxTotalProgress;
2158     for (int i = 0; i < super.progressListeners.length; i++) {
2159         super.progressListeners[i].changed (event);
2160     }
2161     return XPCOM.NS_OK;
2162 }
2163 
2164 extern(System)
2165 nsresult OnLocationChange (nsIWebProgress aWebProgress, nsIRequest aRequest, nsIURI aLocation) {
2166     /*
2167     * Feature in Mozilla.  When a page is loaded via setText before a previous
2168     * setText page load has completed, the expected OnStateChange STATE_STOP for the
2169     * original setText never arrives because it gets replaced by the OnStateChange
2170     * STATE_STOP for the new request.  This results in the request field never being
2171     * cleared because the original request's OnStateChange STATE_STOP is still expected
2172     * (but never arrives).  To handle this case, the request field is updated to the new
2173     * overriding request since its OnStateChange STATE_STOP will be received next.
2174     */
2175     if (request !is null && request !is aRequest) request = aRequest;
2176 
2177     if (awaitingNavigate || locationListeners.length is 0) return XPCOM.NS_OK;
2178 
2179     //nsIWebProgress webProgress = new nsIWebProgress (aWebProgress);
2180     
2181     nsIDOMWindow domWindow;
2182     //ptrdiff_t[] aDOMWindow = new ptrdiff_t[1];
2183     int rc = aWebProgress.GetDOMWindow (&domWindow);
2184     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2185     if (domWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2186     
2187     //nsIDOMWindow domWindow = new nsIDOMWindow (aDOMWindow[0]);
2188     //ptrdiff_t[] aTop = new ptrdiff_t[1];
2189     nsIDOMWindow topWindow;
2190     rc = domWindow.GetTop (&topWindow);
2191     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2192     if (topWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2193     domWindow.Release ();
2194     
2195     //nsIDOMWindow topWindow = new nsIDOMWindow (aTop[0]);
2196     topWindow.Release ();
2197     
2198     //nsIURI location = new nsIURI (aLocation);
2199     scope auto aSpec = new nsEmbedCString;
2200     aLocation.GetSpec (cast(nsACString*)aSpec);
2201     //int length = XPCOM.nsEmbedCString_Length (aSpec);
2202     //ptrdiff_t buffer = XPCOM.nsEmbedCString_get (aSpec);
2203     //byte[] dest = new byte[length];
2204     //XPCOM.memmove (dest, buffer, length);
2205     //XPCOM.nsEmbedCString_delete (aSpec);
2206     String url = aSpec.toString;
2207 
2208     /*
2209      * As of Mozilla 1.8, the first time that a page is displayed, regardless of
2210      * whether it's via Browser.setURL() or Browser.setText(), the GRE navigates
2211      * to about:blank and fires the corresponding navigation events.  Do not send
2212      * this event on to the user since it is not expected.
2213      */
2214     if (!IsPre_1_8 && aRequest is null && url.startsWith (ABOUT_BLANK)) return XPCOM.NS_OK;
2215 
2216     LocationEvent event = new LocationEvent (browser);
2217     event.display = browser.getDisplay ();
2218     event.widget = browser;
2219     event.location = url;
2220     /*
2221      * If the URI indicates that the page is being rendered from memory
2222      * (via setText()) then set it to about:blank to be consistent with IE.
2223      */
2224     if (event.location.equals (URI_FROMMEMORY)) event.location = ABOUT_BLANK;
2225     event.top = topWindow is domWindow;
2226     for (int i = 0; i < locationListeners.length; i++) {
2227         locationListeners[i].changed (event);
2228     }
2229     return XPCOM.NS_OK;
2230 }
2231 
2232 extern(System)
2233 nsresult OnStatusChange (nsIWebProgress aWebProgress, nsIRequest aRequest, nsresult aStatus, PRUnichar* aMessage) {
2234     if (awaitingNavigate || statusTextListeners.length is 0) return XPCOM.NS_OK;
2235     StatusTextEvent event = new StatusTextEvent (browser);
2236     event.display = browser.getDisplay ();
2237     event.widget = browser;
2238     //int length = XPCOM.strlen_PRUnichar (aMessage);
2239     //char[] dest = new char[length];
2240     //XPCOM.memmove (dest, aMessage, length * 2);
2241     event.text = String_valueOf(fromString16z(aMessage));
2242     for (int i = 0; i < statusTextListeners.length; i++) {
2243         statusTextListeners[i].changed (event);
2244     }
2245     return XPCOM.NS_OK;
2246 }       
2247 
2248 extern(System)
2249 nsresult OnSecurityChange (nsIWebProgress aWebProgress, nsIRequest aRequest, PRUint32 state) {
2250     return XPCOM.NS_OK;
2251 }
2252 
2253 /* nsIWebBrowserChrome */
2254 
2255 extern(System)
2256 nsresult SetStatus (PRUint32 statusType, PRUnichar* status) {
2257     if (awaitingNavigate || statusTextListeners.length is 0) return XPCOM.NS_OK;
2258     StatusTextEvent event = new StatusTextEvent (browser);
2259     event.display = browser.getDisplay ();
2260     event.widget = browser;
2261     //int length = XPCOM.strlen_PRUnichar (status);
2262     //char[] dest = new char[length];
2263     //XPCOM.memmove (dest, status, length * 2);
2264     //String string = new String (dest);
2265     event.text = String_valueOf(fromString16z(status));
2266     for (int i = 0; i < statusTextListeners.length; i++) {
2267         statusTextListeners[i].changed (event);
2268     }
2269     return XPCOM.NS_OK;
2270 }
2271 
2272 extern(System)
2273 nsresult GetWebBrowser (nsIWebBrowser* aWebBrowser) {
2274     //ptrdiff_t[] ret = new ptrdiff_t[1];   
2275     if (webBrowser !is null) {
2276         webBrowser.AddRef ();
2277         *aWebBrowser = webBrowser;  
2278     }
2279     //XPCOM.memmove (aWebBrowser, ret, C.PTR_SIZEOF);
2280     return XPCOM.NS_OK;
2281 }
2282 
2283 extern(System)
2284 nsresult SetWebBrowser (nsIWebBrowser aWebBrowser) {
2285     if (webBrowser !is null) webBrowser.Release ();
2286     webBrowser = aWebBrowser !is null ? cast(nsIWebBrowser)cast(void*)aWebBrowser : null;                
2287     return XPCOM.NS_OK;
2288 }
2289 
2290 extern(System)
2291 nsresult GetChromeFlags (PRUint32* aChromeFlags) {
2292     //int[] ret = new int[1];
2293     *aChromeFlags = chromeFlags;
2294     //XPCOM.memmove (aChromeFlags, ret, 4); /* PRUint32 */
2295     return XPCOM.NS_OK;
2296 }
2297 
2298 extern(System)
2299 nsresult SetChromeFlags (PRUint32 aChromeFlags) {
2300     chromeFlags = aChromeFlags;
2301     return XPCOM.NS_OK;
2302 }
2303 
2304 extern(System)
2305 nsresult DestroyBrowserWindow () {
2306     WindowEvent newEvent = new WindowEvent (browser);
2307     newEvent.display = browser.getDisplay ();
2308     newEvent.widget = browser;
2309     for (int i = 0; i < closeWindowListeners.length; i++) {
2310         closeWindowListeners[i].close (newEvent);
2311     }
2312     /*
2313     * Note on Mozilla.  The DestroyBrowserWindow notification cannot be cancelled.
2314     * The browser widget cannot be used after this notification has been received.
2315     * The application is advised to close the window hosting the browser widget.
2316     * The browser widget must be disposed in all cases.
2317     */
2318     browser.dispose ();
2319     return XPCOM.NS_OK;
2320 }
2321 
2322 extern(System)
2323 nsresult SizeBrowserTo (PRInt32 aCX, PRInt32 aCY) {
2324     size = new Point (aCX, aCY);
2325     bool isChrome = (chromeFlags & nsIWebBrowserChrome.CHROME_OPENAS_CHROME) !is 0;
2326     if (isChrome) {
2327         Shell shell = browser.getShell ();
2328         shell.setSize (shell.computeSize (size.x, size.y));
2329     }
2330     return XPCOM.NS_OK;
2331 }
2332 
2333 extern(System)
2334 nsresult ShowAsModal () {
2335     //ptrdiff_t[] result = new ptrdiff_t[1];
2336     nsIServiceManager serviceManager;
2337     int rc = XPCOM.NS_GetServiceManager (&serviceManager);
2338     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2339     if (serviceManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2340 
2341     //nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
2342     //result[0] = 0;
2343     //byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_CONTEXTSTACK_CONTRACTID, true);
2344     nsIJSContextStack stack;
2345     rc = serviceManager.GetServiceByContractID (XPCOM.NS_CONTEXTSTACK_CONTRACTID.ptr, &nsIJSContextStack.IID, cast(void**)&stack);
2346     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2347     if (stack is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2348     serviceManager.Release ();
2349 
2350     //nsIJSContextStack stack = new nsIJSContextStack (result[0]);
2351     //result[0] = 0;
2352     rc = stack.Push (null);
2353     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2354 
2355     Shell shell = browser.getShell ();
2356     Display display = browser.getDisplay ();
2357     while (!shell.isDisposed ()) {
2358         if (!display.readAndDispatch ()) display.sleep ();
2359     }
2360     JSContext* result;
2361     rc = stack.Pop (&result);
2362     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2363     stack.Release ();
2364     return XPCOM.NS_OK;
2365 }
2366 
2367 extern(System)
2368 nsresult IsWindowModal (PRBool* retval) {
2369     *retval = (chromeFlags & nsIWebBrowserChrome.CHROME_MODAL) !is 0 ? 1 : 0;
2370     //XPCOM.memmove (retval, new int[] {result}, 4); /* PRBool */
2371     return XPCOM.NS_OK;
2372 }
2373 
2374 extern(System)
2375 nsresult ExitModalEventLoop (nsresult aStatus) {
2376     return XPCOM.NS_OK;
2377 }
2378 
2379 /* nsIEmbeddingSiteWindow */ 
2380 
2381 extern(System)
2382 nsresult SetDimensions (PRUint32 flags, PRInt32 x, PRInt32 y, PRInt32 cx, PRInt32 cy) {
2383     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION) !is 0) {
2384         location = new Point (x, y);
2385         browser.getShell ().setLocation (x, y);
2386     }
2387     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) !is 0) {
2388         browser.setSize (cx, cy);
2389     }
2390     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER) !is 0) {
2391         browser.getShell ().setSize (cx, cy);
2392     }
2393     return XPCOM.NS_OK;
2394 }
2395 
2396 extern(System)
2397 nsresult GetDimensions (PRUint32 flags, PRInt32* x, PRInt32* y, PRInt32* cx, PRInt32* cy) {
2398     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_POSITION) !is 0) {
2399         Point location = browser.getShell ().getLocation ();
2400         if (x !is null) *x = location.x; /* PRInt32 */
2401         if (y !is null) *y = location.y; /* PRInt32 */
2402     }
2403     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_INNER) !is 0) {
2404         Point size = browser.getSize ();
2405         if (cx !is null) *cx = size.x; /* PRInt32 */
2406         if (cy !is null) *cy = size.y; /* PRInt32 */
2407     }
2408     if ((flags & nsIEmbeddingSiteWindow.DIM_FLAGS_SIZE_OUTER) !is 0) {
2409         Point size = browser.getShell().getSize ();
2410         if (cx !is null) *cx = size.x; /* PRInt32 */
2411         if (cy !is null) *cy = size.y; /* PRInt32 */
2412     }
2413     return XPCOM.NS_OK;
2414 }
2415 
2416 extern(System)
2417 nsresult SetFocus () {
2418     //ptrdiff_t[] result = new ptrdiff_t[1];
2419     nsIBaseWindow baseWindow;
2420     int rc = webBrowser.QueryInterface (&nsIBaseWindow.IID, cast(void**)&baseWindow);
2421     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2422     if (baseWindow is null) error (XPCOM.NS_ERROR_NO_INTERFACE, __FILE__, __LINE__);
2423     
2424     //nsIBaseWindow baseWindow = new nsIBaseWindow (result[0]);
2425     rc = baseWindow.SetFocus ();
2426     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2427     baseWindow.Release ();
2428 
2429     /*
2430     * Note. Mozilla notifies here that one of the children took
2431     * focus. This could or should be used to fire an SWT.FOCUS_IN
2432     * event on Browser focus listeners.
2433     */
2434     return XPCOM.NS_OK;         
2435 }   
2436 
2437 extern(System)
2438 nsresult GetVisibility (PRBool* aVisibility) {
2439     bool visible = browser.isVisible () && !browser.getShell ().getMinimized ();
2440     *aVisibility = visible ? 1 : 0;
2441     //XPCOM.memmove (aVisibility, new int[] {visible ? 1 : 0}, 4); /* PRBool */
2442     return XPCOM.NS_OK;
2443 }
2444 
2445 extern(System)
2446 nsresult SetVisibility (PRBool aVisibility) {
2447     if (isChild) {
2448         WindowEvent event = new WindowEvent (browser);
2449         event.display = browser.getDisplay ();
2450         event.widget = browser;
2451         if (aVisibility !is 0) {
2452             /*
2453             * Bug in Mozilla.  When the JavaScript window.open is executed, Mozilla
2454             * fires multiple SetVisibility 1 notifications.  The workaround is
2455             * to ignore subsequent notifications. 
2456             */
2457             if (!visible) {
2458                 visible = true;
2459                 event.location = location;
2460                 event.size = size;
2461                 event.addressBar = (chromeFlags & nsIWebBrowserChrome.CHROME_LOCATIONBAR) !is 0;
2462                 event.menuBar = (chromeFlags & nsIWebBrowserChrome.CHROME_MENUBAR) !is 0;
2463                 event.statusBar = (chromeFlags & nsIWebBrowserChrome.CHROME_STATUSBAR) !is 0;
2464                 event.toolBar = (chromeFlags & nsIWebBrowserChrome.CHROME_TOOLBAR) !is 0;
2465                 for (int i = 0; i < visibilityWindowListeners.length; i++) {
2466                     visibilityWindowListeners[i].show (event);
2467                 }
2468                 location = null;
2469                 size = null;
2470             }
2471         } else {
2472             visible = false;
2473             for (int i = 0; i < visibilityWindowListeners.length; i++) {
2474                 visibilityWindowListeners[i].hide (event);
2475             }
2476         }
2477     } else {
2478         visible = aVisibility !is 0;
2479     }
2480     return XPCOM.NS_OK;         
2481 }
2482 
2483 extern(System)
2484 nsresult GetTitle (PRUnichar** aTitle) {
2485     return XPCOM.NS_OK;         
2486 }
2487  
2488 extern(System)
2489 nsresult SetTitle (PRUnichar* aTitle) {
2490     if (awaitingNavigate || titleListeners.length is 0) return XPCOM.NS_OK;
2491     TitleEvent event = new TitleEvent (browser);
2492     event.display = browser.getDisplay ();
2493     event.widget = browser;
2494     /*
2495     * To be consistent with other platforms the title event should
2496     * contain the page's url if the page does not contain a <title>
2497     * tag. 
2498     */
2499     int length = XPCOM.strlen_PRUnichar (aTitle);
2500     if (length > 0) {
2501         //char[] dest = new char[length];
2502         //XPCOM.memmove (dest, aTitle, length * 2);
2503         event.title = String_valueOf(fromString16z(aTitle));
2504     } else {
2505         event.title = getUrl ();
2506     }
2507     for (int i = 0; i < titleListeners.length; i++) {
2508         titleListeners[i].changed (event);
2509     }
2510     return XPCOM.NS_OK;         
2511 }
2512 
2513 extern(System)
2514 nsresult GetSiteWindow (void** aSiteWindow) {
2515     /*
2516     * Note.  The handle is expected to be an HWND on Windows and
2517     * a GtkWidget* on GTK.  This callback is invoked on Windows
2518     * when the javascript window.print is invoked and the print
2519     * dialog comes up. If no handle is returned, the print dialog
2520     * does not come up on this platform.  
2521     */
2522     *aSiteWindow = cast(void*) embedHandle;
2523     return XPCOM.NS_OK;         
2524 }  
2525  
2526 /* nsIWebBrowserChromeFocus */
2527 
2528 extern(System)
2529 nsresult FocusNextElement () {
2530     /*
2531     * Bug in Mozilla embedding API.  Mozilla takes back the focus after sending
2532     * this event.  This prevents tabbing out of Mozilla. This behaviour can be reproduced
2533     * with the Mozilla application TestGtkEmbed.  The workaround is to
2534     * send the traversal notification after this callback returns.
2535     */
2536     browser.getDisplay ().asyncExec (new class() Runnable {
2537         public void run () {
2538             if (browser.isDisposed ()) return;
2539             browser.traverse (SWT.TRAVERSE_TAB_NEXT);
2540         }
2541     });
2542     return XPCOM.NS_OK;  
2543 }
2544 
2545 extern(System)
2546 nsresult FocusPrevElement () {
2547     /*
2548     * Bug in Mozilla embedding API.  Mozilla takes back the focus after sending
2549     * this event.  This prevents tabbing out of Mozilla. This behaviour can be reproduced
2550     * with the Mozilla application TestGtkEmbed.  The workaround is to
2551     * send the traversal notification after this callback returns.
2552     */
2553     browser.getDisplay ().asyncExec (new class() Runnable {
2554         public void run () {
2555             if (browser.isDisposed ()) return;
2556             browser.traverse (SWT.TRAVERSE_TAB_PREVIOUS);
2557         }
2558     });
2559     return XPCOM.NS_OK;         
2560 }
2561 
2562 /* nsIContextMenuListener */
2563 
2564 extern(System)
2565 nsresult OnShowContextMenu (PRUint32 aContextFlags, nsIDOMEvent aEvent, nsIDOMNode aNode) {
2566     if (awaitingNavigate) return XPCOM.NS_OK;
2567 
2568     //nsIDOMEvent domEvent = new nsIDOMEvent (aEvent);
2569     //ptrdiff_t[] result = new ptrdiff_t[1];
2570     nsIDOMMouseEvent domMouseEvent;
2571     int rc = aEvent.QueryInterface (&nsIDOMMouseEvent.IID, cast(void**)&domMouseEvent);
2572     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2573     if (domMouseEvent is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2574 
2575     //nsIDOMMouseEvent domMouseEvent = new nsIDOMMouseEvent (result[0]);
2576     PRInt32 aScreenX, aScreenY;
2577     rc = domMouseEvent.GetScreenX (&aScreenX);
2578     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2579     rc = domMouseEvent.GetScreenY (&aScreenY);
2580     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2581     domMouseEvent.Release ();
2582     
2583     auto event = new Event;
2584     event.x = aScreenX;
2585     event.y = aScreenY;
2586     browser.notifyListeners (SWT.MenuDetect, event);
2587     if (!event.doit) return XPCOM.NS_OK;
2588     Menu menu = browser.getMenu ();
2589     if (menu !is null && !menu.isDisposed ()) {
2590         if (aScreenX !is event.x || aScreenY !is event.y) {
2591             menu.setLocation (event.x, event.y);
2592         }
2593         menu.setVisible (true);
2594     }
2595     return XPCOM.NS_OK;         
2596 }
2597 
2598 /* nsIURIContentListener */
2599 
2600 extern(System)
2601 nsresult OnStartURIOpen (nsIURI aURI, PRBool* retval) {
2602     if (awaitingNavigate || locationListeners.length is 0) {
2603         *retval = 0;
2604         //XPCOM.memmove (retval, new int[] {0}, 4); /* PRBool */
2605         return XPCOM.NS_OK;
2606     }
2607     //nsIURI location = new nsIURI (aURI);
2608     scope auto aSpec = new nsEmbedCString;
2609     aURI.GetSpec (cast(nsACString*)aSpec);
2610     //int length = XPCOM.nsEmbedCString_Length (aSpec);
2611     //ptrdiff_t buffer = XPCOM.nsEmbedCString_get (aSpec);
2612     //buffer = XPCOM.nsEmbedCString_get (aSpec);
2613     //byte[] dest = new byte[length];
2614     //XPCOM.memmove (dest, buffer, length);
2615     //XPCOM.nsEmbedCString_delete (aSpec);
2616     String value = aSpec.toString;
2617     bool doit = true;
2618     if (request is null) {
2619         /* 
2620          * listeners should not be notified of internal transitions like "javascipt:..."
2621          * because this is an implementation side-effect, not a true navigate
2622          */
2623         if (!value.startsWith (PREFIX_JAVASCRIPT)) {
2624             LocationEvent event = new LocationEvent (browser);
2625             event.display = browser.getDisplay();
2626             event.widget = browser;
2627             event.location = value;
2628             /*
2629              * If the URI indicates that the page is being rendered from memory
2630              * (via setText()) then set it to about:blank to be consistent with IE.
2631              */
2632             if (event.location.equals (URI_FROMMEMORY)) event.location = ABOUT_BLANK;
2633             event.doit = doit;
2634             for (int i = 0; i < locationListeners.length; i++) {
2635                 locationListeners[i].changing (event);
2636             }
2637             doit = event.doit && !browser.isDisposed();
2638         }
2639     }
2640     *retval = doit ? 0 : 1;
2641     //XPCOM.memmove (retval, new int[] {doit ? 0 : 1}, 4); /* PRBool */
2642     return XPCOM.NS_OK;
2643 }
2644 
2645 extern(System)
2646 nsresult DoContent (char* aContentType, PRBool aIsContentPreferred, nsIRequest aRequest, nsIStreamListener* aContentHandler, PRBool* retval) {
2647     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2648 }
2649 
2650 extern(System)
2651 nsresult IsPreferred (char* aContentType, char** aDesiredContentType, PRBool* retval) {
2652     bool preferred = false;
2653     auto size = OS.strlen (aContentType);
2654     if (size > 0) {
2655         //byte[] typeBytes = new byte[size + 1];
2656         //XPCOM.memmove (typeBytes, aContentType, size);
2657         String contentType = fromStringz(aContentType)._idup();
2658 
2659         /* do not attempt to handle known problematic content types */
2660         if (!contentType.equals (XPCOM.CONTENT_MAYBETEXT) && !contentType.equals (XPCOM.CONTENT_MULTIPART)) {
2661             /* determine whether browser can handle the content type */
2662             // ptrdiff_t[] result = new ptrdiff_t[1];
2663             nsIServiceManager serviceManager;
2664             int rc = XPCOM.NS_GetServiceManager (&serviceManager);
2665             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2666             if (serviceManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2667             //nsIServiceManager serviceManager = new nsIServiceManager (result[0]);
2668             //result[0] = 0;
2669 
2670             /* First try to use the nsIWebNavigationInfo if it's available (>= mozilla 1.8) */
2671             //byte[] aContractID = MozillaDelegate.wcsToMbcs (null, XPCOM.NS_WEBNAVIGATIONINFO_CONTRACTID, true);
2672             nsIWebNavigationInfo info;
2673             rc = serviceManager.GetServiceByContractID (XPCOM.NS_WEBNAVIGATIONINFO_CONTRACTID.ptr, &nsIWebNavigationInfo.IID, cast(void**)&info);
2674             if (rc is XPCOM.NS_OK) {
2675                 //byte[] bytes = MozillaDelegate.wcsToMbcs (null, contentType, true);
2676                 scope auto typePtr = new nsEmbedCString(contentType);
2677                 //nsIWebNavigationInfo info = new nsIWebNavigationInfo (result[0]);
2678                 //result[0] = 0;
2679                 PRUint32 isSupportedResult; /* PRUint32 */
2680                 rc = info.IsTypeSupported (cast(nsACString*)typePtr, null, &isSupportedResult);
2681                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2682                 info.Release ();
2683                 //XPCOM.nsEmbedCString_delete (typePtr);
2684                 preferred = isSupportedResult !is 0;
2685             } else {
2686                 /* nsIWebNavigationInfo is not available, so do the type lookup */
2687                 //result[0] = 0;
2688                 nsICategoryManager categoryManager;
2689                 rc = serviceManager.GetService (&XPCOM.NS_CATEGORYMANAGER_CID, &nsICategoryManager.IID, cast(void**)&categoryManager);
2690                 if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2691                 if (categoryManager is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2692 
2693                 //nsICategoryManager categoryManager = new nsICategoryManager (result[0]);
2694                 //result[0] = 0;
2695                 auto categoryBytes = "Gecko-Content-Viewers".ptr; //$NON-NLS-1$
2696                 char* result;
2697                 rc = categoryManager.GetCategoryEntry (categoryBytes, aContentType, &result);
2698                 categoryManager.Release ();
2699                 /* if no viewer for the content type is registered then rc is XPCOM.NS_ERROR_NOT_AVAILABLE */
2700                 preferred = rc is XPCOM.NS_OK;
2701             }
2702             serviceManager.Release ();
2703         }
2704     }
2705 
2706     *retval = preferred ? 1 : 0; /* PRBool */
2707     if (preferred) {
2708         *aDesiredContentType = null;
2709     }
2710     return XPCOM.NS_OK;
2711 }
2712 
2713 extern(System)
2714 nsresult CanHandleContent (char* aContentType, PRBool aIsContentPreferred, char** aDesiredContentType, PRBool* retval) {
2715     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2716 }
2717 
2718 extern(System)
2719 nsresult GetLoadCookie (nsISupports* aLoadCookie) {
2720     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2721 }
2722 
2723 extern(System)
2724 nsresult SetLoadCookie (nsISupports aLoadCookie) {
2725     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2726 }
2727 
2728 extern(System)
2729 nsresult GetParentContentListener (nsIURIContentListener* aParentContentListener) {
2730     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2731 }
2732 
2733 extern(System)
2734 nsresult SetParentContentListener (nsIURIContentListener aParentContentListener) {
2735     return XPCOM.NS_ERROR_NOT_IMPLEMENTED;
2736 }
2737 
2738 /* nsITooltipListener */
2739 
2740 extern(System)
2741 nsresult OnShowTooltip (PRInt32 aXCoords, PRInt32 aYCoords, PRUnichar* aTipText) {
2742     if (awaitingNavigate) return XPCOM.NS_OK;
2743 
2744     //int length = XPCOM.strlen_PRUnichar (aTipText);
2745     //char[] dest = new char[length];
2746     //XPCOM.memmove (dest, aTipText, length * 2);
2747     String text = String_valueOf(fromString16z(aTipText));
2748     if (tip !is null && !tip.isDisposed ()) tip.dispose ();
2749     Display display = browser.getDisplay ();
2750     Shell parent = browser.getShell ();
2751     tip = new Shell (parent, SWT.ON_TOP);
2752     tip.setLayout (new FillLayout());
2753     Label label = new Label (tip, SWT.CENTER);
2754     label.setForeground (display.getSystemColor (SWT.COLOR_INFO_FOREGROUND));
2755     label.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND));
2756     label.setText (text);
2757     /*
2758     * Bug in Mozilla embedded API.  Tooltip coordinates are wrong for 
2759     * elements inside an inline frame (IFrame tag).  The workaround is 
2760     * to position the tooltip based on the mouse cursor location.
2761     */
2762     Point point = display.getCursorLocation ();
2763     /* Assuming cursor is 21x21 because this is the size of
2764      * the arrow cursor on Windows
2765      */ 
2766     point.y += 21;
2767     tip.setLocation (point);
2768     tip.pack ();
2769     tip.setVisible (true);
2770     return XPCOM.NS_OK;
2771 }
2772 
2773 extern(System)
2774 nsresult OnHideTooltip () {
2775     if (tip !is null && !tip.isDisposed ()) tip.dispose ();
2776     tip = null;
2777     return XPCOM.NS_OK;
2778 }
2779 
2780 /* nsIDOMEventListener */
2781 
2782 extern(System)
2783 nsresult HandleEvent (nsIDOMEvent event) {
2784     //nsIDOMEvent domEvent = new nsIDOMEvent (event);
2785 
2786     scope auto type = new nsEmbedString;
2787     int rc = event.GetType (cast(nsAString*)type);
2788     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2789     //int length = XPCOM.nsEmbedString_Length (type);
2790     //ptrdiff_t buffer = XPCOM.nsEmbedString_get (type);
2791     //char[] chars = new char[length];
2792     //XPCOM.memmove (chars, buffer, length * 2);
2793     String typeString = type.toString;
2794     //XPCOM.nsEmbedString_delete (type);
2795 
2796     if (XPCOM.DOMEVENT_UNLOAD.equals (typeString)) {
2797         //ptrdiff_t[] result = new ptrdiff_t[1];
2798         nsIDOMEventTarget target;
2799         rc = event.GetCurrentTarget (&target);
2800         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2801         if (target is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2802 
2803         //nsIDOMEventTarget target = new nsIDOMEventTarget (result[0]);
2804         unhookDOMListeners (target);
2805         target.Release ();
2806         return XPCOM.NS_OK;
2807     }
2808 
2809     if (XPCOM.DOMEVENT_FOCUS.equals (typeString)) {
2810         mozDelegate.handleFocus ();
2811         return XPCOM.NS_OK;
2812     }
2813 
2814     if (XPCOM.DOMEVENT_KEYDOWN.equals (typeString)) {
2815         //ptrdiff_t[] result = new ptrdiff_t[1];
2816         nsIDOMKeyEvent domKeyEvent;
2817         rc = event.QueryInterface (&nsIDOMKeyEvent.IID, cast(void**)&domKeyEvent);
2818         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2819         if (domKeyEvent is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2820         //nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
2821         //result[0] = 0;
2822 
2823         PRUint32 aKeyCode; /* PRUint32 */
2824         rc = domKeyEvent.GetKeyCode (&aKeyCode);
2825         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2826         int keyCode = super.translateKey (aKeyCode);
2827 
2828         /*
2829         * if keyCode is lastKeyCode then either a repeating key like Shift
2830         * is being held or a key for which key events are not sent has been
2831         * pressed.  In both of these cases a KeyDown should not be sent.
2832         */
2833         if (keyCode !is lastKeyCode) {
2834             lastKeyCode = keyCode;
2835             switch (keyCode) {
2836                 case SWT.SHIFT:
2837                 case SWT.CONTROL:
2838                 case SWT.ALT:
2839                 case SWT.CAPS_LOCK:
2840                 case SWT.NUM_LOCK:
2841                 case SWT.SCROLL_LOCK:
2842                 case SWT.COMMAND: {
2843                     /* keypress events will not be received for these keys, so send KeyDowns for them now */
2844                     PRBool aAltKey, aCtrlKey, aShiftKey, aMetaKey; /* PRBool */
2845                     rc = domKeyEvent.GetAltKey (&aAltKey);
2846                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2847                     rc = domKeyEvent.GetCtrlKey (&aCtrlKey);
2848                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2849                     rc = domKeyEvent.GetShiftKey (&aShiftKey);
2850                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2851                     rc = domKeyEvent.GetMetaKey (&aMetaKey);
2852                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2853 
2854                     Event keyEvent = new Event ();
2855                     keyEvent.widget = browser;
2856                     keyEvent.type = SWT.KeyDown;
2857                     keyEvent.keyCode = keyCode;
2858                     keyEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0 ? SWT.CTRL : 0) | (aShiftKey !is 0 ? SWT.SHIFT : 0) | (aMetaKey !is 0 ? SWT.COMMAND : 0);
2859                     keyEvent.stateMask &= ~keyCode;     /* remove current keydown if it's a state key */
2860                     browser.notifyListeners (keyEvent.type, keyEvent);
2861                     if (!keyEvent.doit) {
2862                         event.PreventDefault ();
2863                     }
2864                     break;
2865                 }
2866                 default: {
2867                     /* 
2868                     * If the keydown has Meta (but not Meta+Ctrl) as a modifier then send a KeyDown event for it here
2869                     * because a corresponding keypress event will not be received for it from the DOM.  If the keydown
2870                     * does not have Meta as a modifier, or has Meta+Ctrl as a modifier, then then do nothing here
2871                     * because its KeyDown event will be sent from the keypress listener.
2872                     */
2873                     PRBool aMetaKey; /* PRBool */
2874                     rc = domKeyEvent.GetMetaKey (&aMetaKey);
2875                     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2876                     if (aMetaKey !is 0) {
2877                         PRBool aCtrlKey; /* PRBool */
2878                         rc = domKeyEvent.GetCtrlKey (&aCtrlKey);
2879                         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2880                         if (aCtrlKey is 0) {
2881                             PRBool aAltKey, aShiftKey; /* PRBool */
2882                             rc = domKeyEvent.GetAltKey (&aAltKey);
2883                             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2884                             rc = domKeyEvent.GetShiftKey (&aShiftKey);
2885                             if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2886 
2887                             Event keyEvent = new Event ();
2888                             keyEvent.widget = browser;
2889                             keyEvent.type = SWT.KeyDown;
2890                             keyEvent.keyCode = lastKeyCode;
2891                             keyEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0? SWT.CTRL : 0) | (aShiftKey !is 0? SWT.SHIFT : 0) | (aMetaKey !is 0? SWT.COMMAND : 0);
2892                             browser.notifyListeners (keyEvent.type, keyEvent);
2893                             if (!keyEvent.doit) {
2894                                 event.PreventDefault ();
2895                             }
2896                         }
2897                     }
2898                 }
2899             }
2900         }
2901 
2902         domKeyEvent.Release ();
2903         return XPCOM.NS_OK;
2904     }
2905 
2906     if (XPCOM.DOMEVENT_KEYPRESS.equals (typeString)) {
2907         /*
2908         * if keydown could not determine a keycode for this key then it's a
2909         * key for which key events are not sent (eg.- the Windows key)
2910         */
2911         if (lastKeyCode is 0) return XPCOM.NS_OK;
2912 
2913         /*
2914         * On linux only, unexpected keypress events are received for some
2915         * modifier keys.  The workaround is to ignore these events since
2916         * KeyDown events are sent for these keys in the keydown listener.  
2917         */
2918         switch (lastKeyCode) {
2919             case SWT.CAPS_LOCK:
2920             case SWT.NUM_LOCK:
2921             case SWT.SCROLL_LOCK: return XPCOM.NS_OK;
2922             default: break;
2923         }
2924 
2925         //ptrdiff_t[] result = new ptrdiff_t[1];
2926         nsIDOMKeyEvent domKeyEvent;
2927         rc = event.QueryInterface (&nsIDOMKeyEvent.IID, cast(void**)&domKeyEvent);
2928         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2929         if (domKeyEvent is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2930         //nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
2931         //result[0] = 0;
2932 
2933         PRBool aAltKey, aCtrlKey, aShiftKey, aMetaKey; /* PRBool */
2934         rc = domKeyEvent.GetAltKey (&aAltKey);
2935         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2936         rc = domKeyEvent.GetCtrlKey (&aCtrlKey);
2937         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2938         rc = domKeyEvent.GetShiftKey (&aShiftKey);
2939         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2940         rc = domKeyEvent.GetMetaKey (&aMetaKey);
2941         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2942         domKeyEvent.Release ();
2943 
2944         PRUint32 aCharCode; /* PRUint32 */
2945         rc = domKeyEvent.GetCharCode (&aCharCode);
2946         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2947         lastCharCode = aCharCode;
2948         if (lastCharCode is 0) {
2949             switch (lastKeyCode) {
2950                 case SWT.TAB: lastCharCode = SWT.TAB; break;
2951                 case SWT.CR: lastCharCode = SWT.CR; break;
2952                 case SWT.BS: lastCharCode = SWT.BS; break;
2953                 case SWT.ESC: lastCharCode = SWT.ESC; break;
2954                 case SWT.DEL: lastCharCode = SWT.DEL; break;
2955                 default: break;
2956             }
2957         }
2958         if (aCtrlKey !is 0 && (0 <= lastCharCode && lastCharCode <= 0x7F)) {
2959             if ('a'  <= lastCharCode && lastCharCode <= 'z') lastCharCode -= 'a' - 'A';
2960             if (64 <= lastCharCode && lastCharCode <= 95) lastCharCode -= 64;
2961         }
2962 
2963         Event keyEvent = new Event ();
2964         keyEvent.widget = browser;
2965         keyEvent.type = SWT.KeyDown;
2966         keyEvent.keyCode = lastKeyCode;
2967         keyEvent.character = cast(wchar)lastCharCode;
2968         keyEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0 ? SWT.CTRL : 0) | (aShiftKey !is 0 ? SWT.SHIFT : 0) | (aMetaKey !is 0 ? SWT.COMMAND : 0);
2969         browser.notifyListeners (keyEvent.type, keyEvent);
2970         if (!keyEvent.doit) {
2971             event.PreventDefault ();
2972         }
2973         return XPCOM.NS_OK;
2974     }
2975 
2976     if (XPCOM.DOMEVENT_KEYUP.equals (typeString)) {
2977         //ptrdiff_t[] result = new ptrdiff_t[1];
2978         nsIDOMKeyEvent domKeyEvent;
2979         rc = event.QueryInterface (&nsIDOMKeyEvent.IID, cast(void**)&domKeyEvent);
2980         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2981         if (domKeyEvent is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
2982         //nsIDOMKeyEvent domKeyEvent = new nsIDOMKeyEvent (result[0]);
2983         //result[0] = 0;
2984 
2985         PRUint32 aKeyCode; /* PRUint32 */
2986         rc = domKeyEvent.GetKeyCode (&aKeyCode);
2987         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
2988         int keyCode = super.translateKey (aKeyCode);
2989         if (keyCode is 0) {
2990             /* indicates a key for which key events are not sent */
2991             domKeyEvent.Release ();
2992             return XPCOM.NS_OK;
2993         }
2994         if (keyCode !is lastKeyCode) {
2995             /* keyup does not correspond to the last keydown */
2996             lastKeyCode = keyCode;
2997             lastCharCode = 0;
2998         }
2999 
3000         PRBool aAltKey, aCtrlKey, aShiftKey, aMetaKey; /* PRBool */
3001         rc = domKeyEvent.GetAltKey (&aAltKey);
3002         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3003         rc = domKeyEvent.GetCtrlKey (&aCtrlKey);
3004         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3005         rc = domKeyEvent.GetShiftKey (&aShiftKey);
3006         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3007         rc = domKeyEvent.GetMetaKey (&aMetaKey);
3008         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3009         domKeyEvent.Release ();
3010 
3011         Event keyEvent = new Event ();
3012         keyEvent.widget = browser;
3013         keyEvent.type = SWT.KeyUp;
3014         keyEvent.keyCode = lastKeyCode;
3015         keyEvent.character = cast(wchar)lastCharCode;
3016         keyEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0 ? SWT.CTRL : 0) | (aShiftKey !is 0 ? SWT.SHIFT : 0) | (aMetaKey !is 0 ? SWT.COMMAND : 0);
3017         switch (lastKeyCode) {
3018             case SWT.SHIFT:
3019             case SWT.CONTROL:
3020             case SWT.ALT:
3021             case SWT.COMMAND: {
3022                 keyEvent.stateMask |= lastKeyCode;
3023             }
3024             default: break;
3025         }
3026         browser.notifyListeners (keyEvent.type, keyEvent);
3027         if (!keyEvent.doit) {
3028             event.PreventDefault ();
3029         }
3030         lastKeyCode = lastCharCode = 0;
3031         return XPCOM.NS_OK;
3032     }
3033 
3034     /* mouse event */
3035 
3036     //ptrdiff_t[] result = new ptrdiff_t[1];
3037     nsIDOMMouseEvent domMouseEvent;
3038     rc = event.QueryInterface (&nsIDOMMouseEvent.IID, cast(void**)&domMouseEvent);
3039     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3040     if (domMouseEvent is null) error (XPCOM.NS_NOINTERFACE, __FILE__, __LINE__);
3041     //nsIDOMMouseEvent domMouseEvent = new nsIDOMMouseEvent (result[0]);
3042     //result[0] = 0;
3043 
3044     /*
3045      * MouseOver and MouseOut events are fired any time the mouse enters or exits
3046      * any element within the Browser.  To ensure that SWT events are only
3047      * fired for mouse movements into or out of the Browser, do not fire an
3048      * event if the element being exited (on MouseOver) or entered (on MouseExit)
3049      * is within the Browser.
3050      */
3051     if (XPCOM.DOMEVENT_MOUSEOVER.equals (typeString) || XPCOM.DOMEVENT_MOUSEOUT.equals (typeString)) {
3052         nsIDOMEventTarget eventTarget;
3053         rc = domMouseEvent.GetRelatedTarget (&eventTarget);
3054         if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3055         if (eventTarget !is null) {
3056             domMouseEvent.Release ();
3057             return XPCOM.NS_OK;
3058         }
3059     }
3060 
3061     PRInt32 aClientX, aClientY, aDetail; /* PRInt32 */
3062     rc = domMouseEvent.GetClientX (&aClientX);
3063     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3064     rc = domMouseEvent.GetClientY (&aClientY);
3065     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3066     rc = domMouseEvent.GetDetail (&aDetail);
3067     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3068     PRUint16 aButton; /* PRUint16 */
3069     rc = domMouseEvent.GetButton (&aButton);
3070     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3071     PRBool aAltKey, aCtrlKey, aShiftKey, aMetaKey; /* PRBool */
3072     rc = domMouseEvent.GetAltKey (&aAltKey);
3073     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3074     rc = domMouseEvent.GetCtrlKey (&aCtrlKey);
3075     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3076     rc = domMouseEvent.GetShiftKey (&aShiftKey);
3077     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3078     rc = domMouseEvent.GetMetaKey (&aMetaKey);
3079     if (rc !is XPCOM.NS_OK) error (rc, __FILE__, __LINE__);
3080     domMouseEvent.Release ();
3081 
3082     Event mouseEvent = new Event ();
3083     mouseEvent.widget = browser;
3084     mouseEvent.x = aClientX; mouseEvent.y = aClientY;
3085     mouseEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0 ? SWT.CTRL : 0) | (aShiftKey !is 0 ? SWT.SHIFT : 0) | (aMetaKey !is 0 ? SWT.COMMAND : 0);
3086 
3087     if (XPCOM.DOMEVENT_MOUSEDOWN.equals (typeString)) {
3088         mozDelegate.handleMouseDown ();
3089         mouseEvent.type = SWT.MouseDown;
3090         mouseEvent.button = aButton + 1;
3091         mouseEvent.count = aDetail;
3092     } else if (XPCOM.DOMEVENT_MOUSEUP.equals (typeString)) {
3093         /*
3094          * Bug on OSX.  For some reason multiple mouseup events come from the DOM
3095          * when button 3 is released on OSX.  The first of these events has a count
3096          * detail and the others do not.  The workaround is to not fire received
3097          * button 3 mouseup events that do not have a count since mouse events
3098          * without a click count are not valid.
3099          */
3100         int button = aButton + 1;
3101         int count = aDetail;
3102         if (count is 0 && button is 3) return XPCOM.NS_OK;
3103         mouseEvent.type = SWT.MouseUp;
3104         mouseEvent.button = button;
3105         mouseEvent.count = count;
3106     } else if (XPCOM.DOMEVENT_MOUSEMOVE.equals (typeString)) {
3107         mouseEvent.type = SWT.MouseMove;
3108     } else if (XPCOM.DOMEVENT_MOUSEWHEEL.equals (typeString)) {
3109         mouseEvent.type = SWT.MouseWheel;
3110         mouseEvent.count = -aDetail;
3111     } else if (XPCOM.DOMEVENT_MOUSEOVER.equals (typeString)) {
3112         mouseEvent.type = SWT.MouseEnter;
3113     } else if (XPCOM.DOMEVENT_MOUSEOUT.equals (typeString)) {
3114         mouseEvent.type = SWT.MouseExit;
3115     } else if (XPCOM.DOMEVENT_MOUSEDRAG.equals (typeString)) {
3116         mouseEvent.type = SWT.DragDetect;
3117         mouseEvent.button = aButton + 1;
3118         switch (mouseEvent.button) {
3119             case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
3120             case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
3121             case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
3122             case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
3123             case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
3124             default: break;
3125         }
3126     }
3127 
3128     browser.notifyListeners (mouseEvent.type, mouseEvent);
3129     if (aDetail is 2 && XPCOM.DOMEVENT_MOUSEDOWN.equals (typeString)) {
3130         mouseEvent = new Event ();
3131         mouseEvent.widget = browser;
3132         mouseEvent.x = aClientX; mouseEvent.y = aClientY;
3133         mouseEvent.stateMask = (aAltKey !is 0 ? SWT.ALT : 0) | (aCtrlKey !is 0 ? SWT.CTRL : 0) | (aShiftKey !is 0 ? SWT.SHIFT : 0) | (aMetaKey !is 0 ? SWT.COMMAND : 0);
3134         mouseEvent.type = SWT.MouseDoubleClick;
3135         mouseEvent.button = aButton + 1;
3136         mouseEvent.count = aDetail;
3137         browser.notifyListeners (mouseEvent.type, mouseEvent);  
3138     }
3139     return XPCOM.NS_OK;
3140 }
3141 }