1 /*******************************************************************************
2 * Copyright (c) 2000, 2016 IBM Corporation and others.
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
12 * IBM Corporation - initial API and implementation
13 *******************************************************************************/
14 package org.eclipse.swt.awt;
18 import java.awt.Canvas;
19 import java.awt.event.*;
20 import java.lang.reflect.*;
23 import org.eclipse.swt.*;
24 import org.eclipse.swt.graphics.Point;
25 import org.eclipse.swt.graphics.Rectangle;
26 import org.eclipse.swt.internal.*;
27 import org.eclipse.swt.internal.win32.*;
28 import org.eclipse.swt.widgets.*;
29 import org.eclipse.swt.widgets.Composite;
32 * This class provides a bridge between SWT and AWT, so that it
33 * is possible to embed AWT components in SWT and vice versa.
35 * @see <a href="http://www.eclipse.org/swt/snippets/#awt">Swing/AWT snippets</a>
36 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
40 public class SWT_AWT {
43 * The name of the embedded Frame class. The default class name
44 * for the platform will be used if <code>null</code>.
46 public static String embeddedFrameClass;
49 * Key for looking up the embedded frame for a Composite using
52 static String EMBEDDED_FRAME_KEY = "org.eclipse.swt.awt.SWT_AWT.embeddedFrame";
54 static boolean loaded, swingInitialized;
56 static native final long getAWTHandle (Canvas canvas);
57 static native final Object initFrame (long handle, String className);
58 static native final void synthesizeWindowActivation (Frame frame, boolean doActivate);
60 static synchronized void loadLibrary () {
63 Toolkit.getDefaultToolkit();
65 * Note that the jawt library is loaded explicitly
66 * because it cannot be found by the library loader.
67 * All exceptions are caught because the library may
68 * have been loaded already.
71 System.loadLibrary("jawt");
72 } catch (Throwable e) {}
73 Library.loadLibrary("swt-awt");
76 static synchronized void initializeSwing() {
77 if (swingInitialized) return;
78 swingInitialized = true;
80 /* Initialize the default focus traversal policy */
81 Class<?> clazz = Class.forName("javax.swing.UIManager");
82 Method method = clazz.getMethod("getDefaults");
83 if (method != null) method.invoke(clazz);
84 } catch (Throwable e) {}
88 * Returns a <code>java.awt.Frame</code> which is the embedded frame
89 * associated with the specified composite.
91 * @param parent the parent <code>Composite</code> of the <code>java.awt.Frame</code>
92 * @return a <code>java.awt.Frame</code> the embedded frame or <code>null</code>.
94 * @exception IllegalArgumentException <ul>
95 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
100 public static Frame getFrame (Composite parent) {
101 if (parent == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
102 if ((parent.getStyle () & SWT.EMBEDDED) == 0) return null;
103 return (Frame)parent.getData(EMBEDDED_FRAME_KEY);
107 * Creates a new <code>java.awt.Frame</code>. This frame is the root for
108 * the AWT components that will be embedded within the composite. In order
109 * for the embedding to succeed, the composite must have been created
110 * with the SWT.EMBEDDED style.
112 * IMPORTANT: As of JDK1.5, the embedded frame does not receive mouse events.
113 * When a lightweight component is added as a child of the embedded frame,
114 * the cursor does not change. In order to work around both these problems, it is
115 * strongly recommended that a heavyweight component such as <code>java.awt.Panel</code>
116 * be added to the frame as the root of all components.
119 * @param parent the parent <code>Composite</code> of the new <code>java.awt.Frame</code>
120 * @return a <code>java.awt.Frame</code> to be the parent of the embedded AWT components
122 * @exception IllegalArgumentException <ul>
123 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
124 * <li>ERROR_INVALID_ARGUMENT - if the parent Composite does not have the SWT.EMBEDDED style</li>
129 public static Frame new_Frame (final Composite parent) {
130 if (parent == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
131 if ((parent.getStyle () & SWT.EMBEDDED) == 0) {
132 SWT.error (SWT.ERROR_INVALID_ARGUMENT);
134 final long handle = parent.handle;
135 final Frame[] result = new Frame[1];
136 final Throwable[] exception = new Throwable[1];
137 Runnable runnable = () -> {
140 * Some JREs have implemented the embedded frame constructor to take an integer
141 * and other JREs take a long. To handle this binary incompatibility, use
142 * reflection to create the embedded frame.
144 String className = embeddedFrameClass != null ? embeddedFrameClass : "sun.awt.windows.WEmbeddedFrame";
146 if (embeddedFrameClass != null) {
147 Class.forName(className);
150 } catch (ClassNotFoundException cne) {
151 SWT.error (SWT.ERROR_NOT_IMPLEMENTED, cne);
152 } catch (Throwable e) {
157 Object value = initFrame(handle, className);
158 if (value == null || !(value instanceof Frame)) {
159 exception [0] = new Throwable("[Error while creating AWT embedded frame]");
160 SWT.error (SWT.ERROR_UNSPECIFIED, exception[0]);
163 result[0] = (Frame) value;
165 synchronized(result) {
170 if (EventQueue.isDispatchThread() || parent.getDisplay().getSyncThread() != null) {
173 EventQueue.invokeLater(runnable);
175 boolean interrupted = false;
176 MSG msg = new MSG ();
177 int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_SENDMESSAGE;
178 while (result[0] == null && exception[0] == null) {
179 OS.PeekMessage (msg, 0, 0, 0, flags);
181 synchronized (result) {
184 } catch (InterruptedException e) {
189 Thread.currentThread().interrupt();
192 if (exception[0] != null) {
193 SWT.error (SWT.ERROR_NOT_IMPLEMENTED, exception[0]);
195 final Frame frame = result[0];
197 parent.setData(EMBEDDED_FRAME_KEY, frame);
199 /* Forward the iconify and deiconify events */
200 final Listener shellListener = e -> {
203 EventQueue.invokeLater(() -> frame.dispatchEvent (new WindowEvent (frame, WindowEvent.WINDOW_DEICONIFIED)));
206 EventQueue.invokeLater(() -> frame.dispatchEvent (new WindowEvent (frame, WindowEvent.WINDOW_ICONIFIED)));
210 Shell shell = parent.getShell ();
211 shell.addListener (SWT.Deiconify, shellListener);
212 shell.addListener (SWT.Iconify, shellListener);
215 * Generate the appropriate events to activate and deactivate
216 * the embedded frame. This is needed in order to make keyboard
217 * focus work properly for lightweights.
219 Listener listener = e -> {
222 Shell shell1 = parent.getShell ();
223 shell1.removeListener (SWT.Deiconify, shellListener);
224 shell1.removeListener (SWT.Iconify, shellListener);
225 parent.setVisible(false);
226 EventQueue.invokeLater(() -> {
229 } catch (Throwable e1) {}
234 EventQueue.invokeLater(() -> {
235 if (frame.isActive()) return;
237 Class<?> clazz = frame.getClass();
238 Method method = clazz.getMethod("synthesizeWindowActivation", boolean.class);
239 if (method != null) method.invoke(frame, Boolean.TRUE);
240 } catch (Throwable e1) {}
244 EventQueue.invokeLater(() -> {
245 if (!frame.isActive()) return;
247 Class<?> clazz = frame.getClass();
248 Method method = clazz.getMethod("synthesizeWindowActivation", boolean.class);
249 if (method != null) method.invoke(frame, Boolean.FALSE);
250 } catch (Throwable e1) {}
255 parent.addListener (SWT.FocusIn, listener);
256 parent.addListener (SWT.Deactivate, listener);
257 parent.addListener (SWT.Dispose, listener);
259 parent.getDisplay().asyncExec(() -> {
260 if (parent.isDisposed()) return;
261 final Rectangle clientArea = DPIUtil.autoScaleUp(parent.getClientArea()); // To Pixels
262 EventQueue.invokeLater(() -> {
263 frame.setSize (clientArea.width, clientArea.height);
271 * Creates a new <code>Shell</code>. This Shell is the root for
272 * the SWT widgets that will be embedded within the AWT canvas.
274 * @param display the display for the new Shell
275 * @param parent the parent <code>java.awt.Canvas</code> of the new Shell
276 * @return a <code>Shell</code> to be the parent of the embedded SWT widgets
278 * @exception IllegalArgumentException <ul>
279 * <li>ERROR_NULL_ARGUMENT - if the display is null</li>
280 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
281 * <li>ERROR_INVALID_ARGUMENT - if the parent's peer is not created</li>
286 public static Shell new_Shell (final Display display, final Canvas parent) {
287 if (display == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
288 if (parent == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
292 handle = getAWTHandle (parent);
293 } catch (Throwable e) {
294 SWT.error (SWT.ERROR_NOT_IMPLEMENTED, e);
296 if (handle == 0) SWT.error (SWT.ERROR_INVALID_ARGUMENT, null, " [peer not created]");
298 final Shell shell = Shell.win32_new (display, handle);
299 final ComponentListener listener = new ComponentAdapter () {
301 public void componentResized (ComponentEvent e) {
302 display.syncExec (() -> {
303 if (shell.isDisposed()) return;
304 Dimension dim = parent.getSize ();
305 shell.setSize(DPIUtil.autoScaleDown(new Point(dim.width, dim.height))); // To Points
309 parent.addComponentListener(listener);
310 shell.addListener(SWT.Dispose, event -> parent.removeComponentListener(listener));
311 shell.setVisible (true);