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.MozillaDelegate;
14 
15 import java.lang.all;
16 
17 version(Tango){
18 import tango.io.Console;
19 } else { // Phobos
20 }
21 
22 import org.eclipse.swt.SWT;
23 import org.eclipse.swt.internal.Converter;
24 import org.eclipse.swt.internal.gtk.OS;
25 import org.eclipse.swt.widgets.Display;
26 import org.eclipse.swt.widgets.Event;
27 import org.eclipse.swt.widgets.Listener;
28 import org.eclipse.swt.widgets.Widget;
29 
30 import org.eclipse.swt.browser.Browser;
31 import org.eclipse.swt.browser.Mozilla;
32 
33 //import org.eclipse.swt.internal.c.glib_object;
34 
35 class MozillaDelegate {
36     Browser browser;
37     gpointer mozillaHandle;
38     GtkWidget* embedHandle;
39     bool hasFocus;
40     Listener listener;
41     //static Callback eventCallback;
42     // static ptrdiff_t eventProc;
43     static const gpointer STOP_PROPOGATE = cast(gpointer)1;
44     static bool IsLinux;
45 
46 static this () {
47     String osName = System.getProperty ("os.name").toLowerCase(); //$NON-NLS-1$
48     IsLinux = osName.startsWith("linux"); //$NON-NLS-1$
49 }
50 
51 this (Browser browser) {
52     //super ();
53     if (!IsLinux) {
54         browser.dispose ();
55         SWT.error (SWT.ERROR_NO_HANDLES, null, " [Unsupported platform]"); //$NON-NLS-1$
56     }
57     this.browser = browser;
58 }
59 
60 static extern(System) int eventProc (GtkWidget* handle, GdkEvent* gdkEvent, gpointer pointer) {
61     GtkWidget* parent = OS.gtk_widget_get_parent (handle);
62     parent = OS.gtk_widget_get_parent (parent);
63     if (parent is null) return 0;
64     Widget widget = Display.getCurrent ().findWidget (parent);
65     if (widget !is null && (cast(Browser)widget) !is null) {
66         return (cast(Mozilla)(cast(Browser)widget).webBrowser).mozDelegate.gtk_event (handle, gdkEvent, pointer);
67     }
68     return 0;
69 }
70 
71 static Browser findBrowser (GtkWidget* handle) {
72     /*
73     * Note.  On GTK, Mozilla is embedded into a GtkHBox handle
74     * and not directly into the parent Composite handle.
75     */
76     GtkWidget* parent = OS.gtk_widget_get_parent (handle);
77     Display display = Display.getCurrent ();
78     return cast(Browser)display.findWidget (parent); 
79 }
80 /*
81 static char[] mbcsToWcs (String codePage, byte [] buffer) {
82     return Converter.mbcsToWcs (codePage, buffer);
83 }
84 
85 static byte[] wcsToMbcs (String codePage, String string, bool terminate) {
86     return Converter.wcsToMbcs (codePage, string, terminate);
87 }
88 */
89 GtkWidget* getHandle () {
90     /*
91     * Bug in Mozilla Linux GTK.  Embedding Mozilla into a GtkFixed
92     * handle causes problems with some Mozilla plug-ins.  For some
93     * reason, the Flash plug-in causes the child of the GtkFixed
94     * handle to be resized to 1 when the Flash document is loaded.
95     * That could be due to gtk_container_resize_children being called
96     * by Mozilla - or one of its plug-ins - on the GtkFixed handle,
97     * causing the child of the GtkFixed handle to be resized to 1.
98     * The workaround is to embed Mozilla into a GtkHBox handle.
99     */
100     embedHandle = OS.gtk_hbox_new (false, 0);
101     OS.gtk_container_add (browser.handle, embedHandle);
102     OS.gtk_widget_show (embedHandle);
103     return embedHandle;
104 }
105 
106 String getLibraryName () {
107     return "libxpcom.so"; //$NON-NLS-1$
108 }
109 
110 /*
111 String getSWTInitLibraryName () {
112     return "swt-xpcominit"; //$NON-NLS-1$
113 }
114 */
115 
116 int gtk_event (GtkWidget* handle, GdkEvent* event, gpointer pointer) {
117     if (event.type is OS.GDK_BUTTON_PRESS) {
118         if (!hasFocus) browser.setFocus ();
119     }
120 
121     /* 
122     * Stop the propagation of events that are not consumed by Mozilla, before
123     * they reach the parent embedder.  These event have already been received.
124     */
125     if (pointer is STOP_PROPOGATE) return 1;
126     return 0;
127 }
128 
129 void handleFocus () {
130     if (hasFocus) return;
131     hasFocus = true;
132     listener = new class() Listener {
133         public void handleEvent (Event event) {
134             if (event.widget is browser) return;
135             (cast(Mozilla)(browser.webBrowser)).Deactivate ();
136             hasFocus = false;
137             browser.getDisplay ().removeFilter (SWT.FocusIn, this);
138             browser.getShell ().removeListener (SWT.Deactivate, this);
139             listener = null;
140         }
141     };
142     browser.getDisplay ().addFilter (SWT.FocusIn, listener);
143     browser.getShell ().addListener (SWT.Deactivate, listener);
144 }
145 
146 void handleMouseDown () {
147     int shellStyle = browser.getShell ().getStyle (); 
148     if ((shellStyle & SWT.ON_TOP) !is 0 && (((shellStyle & SWT.NO_FOCUS) is 0) || ((browser.getStyle () & SWT.NO_FOCUS) is 0))) {
149         browser.getDisplay ().asyncExec (new class() Runnable {
150             public void run () {
151                 if (browser is null || browser.isDisposed ()) return;
152                 (cast(Mozilla)(browser.webBrowser)).Activate ();
153             }
154         });
155     }
156 }
157 
158 bool hookEnterExit () {
159     return false;
160 }
161 
162 void init () { /*
163     if (eventCallback is null) {
164         eventCallback = new Callback (getClass (), "eventProc", 3); //$NON-NLS-1$
165         eventProc = eventCallback.getAddress ();
166         if (eventProc is null) {
167             browser.dispose ();
168             Mozilla.error (SWT.ERROR_NO_MORE_CALLBACKS);
169         }
170     } */
171 
172     /*
173     * Feature in Mozilla.  GtkEvents such as key down, key pressed may be consumed
174     * by Mozilla and never be received by the parent embedder.  The workaround
175     * is to find the top Mozilla gtk widget that receives all the Mozilla GtkEvents,
176     * i.e. the first child of the parent embedder. Then hook event callbacks and
177     * forward the event to the parent embedder before Mozilla received and consumed
178     * them.
179     */
180     GList* list = OS.gtk_container_get_children (embedHandle);
181     if (list !is null) {
182         mozillaHandle = OS.g_list_data (list);
183         OS.g_list_free (list);
184         
185         if (mozillaHandle !is null) {          
186             /* Note. Callback to get events before Mozilla receives and consumes them. */
187             OS.g_signal_connect (mozillaHandle, OS.event.toStringz(), cast(GCallback)&eventProc, null);
188             
189             /* 
190             * Note.  Callback to get the events not consumed by Mozilla - and to block 
191             * them so that they don't get propagated to the parent handle twice.  
192             * This hook is set after Mozilla and is therefore called after Mozilla's 
193             * handler because GTK dispatches events in their order of registration.
194             */
195             OS.g_signal_connect (mozillaHandle, OS.key_press_event.toStringz(), cast(GCallback)&eventProc, STOP_PROPOGATE);
196             OS.g_signal_connect (mozillaHandle, OS.key_release_event.toStringz(), cast(GCallback)&eventProc, STOP_PROPOGATE);
197             OS.g_signal_connect (mozillaHandle, OS.button_press_event.toStringz(), cast(GCallback)&eventProc, STOP_PROPOGATE);
198         }
199     }
200 }
201 
202 bool needsSpinup () {
203     return true;
204 }
205 
206 void onDispose (GtkWidget* embedHandle) {
207     if (listener !is null) {
208         browser.getDisplay ().removeFilter (SWT.FocusIn, listener);
209         browser.getShell ().removeListener (SWT.Deactivate, listener);
210         listener = null;
211     }
212     browser = null;
213 }
214 
215 void setSize (GtkWidget* embedHandle, int width, int height) {
216     OS.gtk_widget_set_size_request (embedHandle, width, height);
217 }
218 
219 }