-/*******************************************************************************\r
- * Copyright (c) 2007 SAS Institute.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * SAS Institute - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.utils.ui.internal.awt;\r
-\r
-import java.awt.AWTEvent;\r
-import java.awt.Dialog;\r
-import java.awt.EventQueue;\r
-import java.awt.Toolkit;\r
-import java.awt.Window;\r
-import java.awt.event.AWTEventListener;\r
-import java.awt.event.ComponentEvent;\r
-import java.awt.event.ComponentListener;\r
-import java.awt.event.WindowEvent;\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import org.eclipse.swt.widgets.Display;\r
-\r
-/**\r
- * A listener that insures the proper modal behavior of Swing dialogs when running\r
- * within a SWT environment. When initialized, it blocks and unblocks SWT input\r
- * as modal Swing dialogs are shown and hidden. \r
- */\r
-@SuppressWarnings({"rawtypes", "unchecked"})\r
-class AwtDialogListener implements AWTEventListener, ComponentListener {\r
- \r
- // modalDialogs should be accessed only from the AWT thread, so no\r
- // synchronization is needed. \r
- private final List modalDialogs = new ArrayList();\r
- private final Display display;\r
- \r
- /**\r
- * Registers this object as an AWT event listener so that Swing dialogs have the \r
- * proper modal behavior in the containing SWT environment. This is called automatically\r
- * when you construct a {@link EmbeddedSwingComposite}, and it\r
- * need not be called separately in that case. \r
- * @param shell \r
- */\r
- AwtDialogListener(Display display) {\r
- assert display != null;\r
- \r
- this.display = display;\r
- Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.WINDOW_EVENT_MASK);\r
- }\r
- \r
- private void handleRemovedDialog(Dialog awtDialog, boolean removeListener) {\r
- assert awtDialog != null;\r
- assert modalDialogs != null;\r
- assert display != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // System.out.println("Remove dialog: " + awtDialog);\r
- if (removeListener) {\r
- awtDialog.removeComponentListener(this);\r
- }\r
- // Note: there is no isModal() check here because the dialog might \r
- // have been changed from modal to non-modal after it was opened. In this case\r
- // the currently visible dialog would still act modal and we'd need to unblock\r
- // SWT here when it goes away.\r
- if (modalDialogs.remove(awtDialog)) {\r
- display.asyncExec(new Runnable() {\r
- public void run() {\r
- SwtInputBlocker.unblock();\r
- }\r
- }); \r
- }\r
- }\r
-\r
- private void handleAddedDialog(final Dialog awtDialog) {\r
- assert awtDialog != null;\r
- assert modalDialogs != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // System.out.println("Add dialog: " + awtDialog);\r
- if (modalDialogs.contains(awtDialog) || !awtDialog.isModal() || !awtDialog.isVisible()) {\r
- return;\r
- }\r
- modalDialogs.add(awtDialog);\r
- awtDialog.addComponentListener(this);\r
- display.asyncExec(new Runnable() {\r
- public void run() {\r
- SwtInputBlocker.block();\r
- }\r
- }); \r
- }\r
- \r
- void requestFocus() {\r
- // TODO: this does not always bring the dialog to the top \r
- // under some Linux desktops/window managers (e.g. metacity under GNOME).\r
- EventQueue.invokeLater(new Runnable() {\r
- public void run() {\r
- assert modalDialogs != null;\r
- \r
- int size = modalDialogs.size();\r
- if (size > 0) {\r
- final Dialog awtDialog = (Dialog)modalDialogs.get(size - 1);\r
-\r
- // In one case, a call to requestFocus() alone does not \r
- // bring the AWT dialog to the top. This happens if the \r
- // dialog is given a null parent frame. When opened, the dialog\r
- // can be hidden by the SWT window even when it obtains focus.\r
- // Calling toFront() solves the problem, but...\r
- //\r
- // There are still problems if the Metal look and feel is in use.\r
- // The SWT window will hide the dialog the first time it is \r
- // selected. Once the dialog is brought back to the front by \r
- // the user, there is no further problem. \r
- //\r
- // Why? It looks like SWT is not being notified of lost focus when \r
- // the Metal dialog first opens; subsequently, when focus is regained, the \r
- // focus gain event is not posted to the SwtInputBlocker. \r
- //\r
- // The workaround is to use Windows look and feel, rather than Metal.\r
- // System.out.println("Bringing to front");\r
-\r
- awtDialog.requestFocus();\r
- awtDialog.toFront();\r
- }\r
- }\r
- });\r
- }\r
-\r
- private void handleOpenedWindow(WindowEvent event) {\r
- assert event != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- Window window = event.getWindow();\r
- if (window instanceof Dialog) {\r
- handleAddedDialog((Dialog)window);\r
- }\r
- }\r
- \r
- private void handleClosedWindow(WindowEvent event) {\r
- assert event != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // Dispose-based close\r
- Window window = event.getWindow();\r
- if (window instanceof Dialog) {\r
- // Remove dialog and component listener\r
- handleRemovedDialog((Dialog)window, true);\r
- }\r
- }\r
-\r
- private void handleClosingWindow(WindowEvent event) {\r
- assert event != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // System-based close \r
- Window window = event.getWindow();\r
- if (window instanceof Dialog) {\r
- final Dialog dialog = (Dialog) window;\r
- // Defer until later. Bad things happen if \r
- // handleRemovedDialog() is called directly from \r
- // this event handler. The Swing dialog does not close\r
- // properly and its modality remains in effect.\r
- EventQueue.invokeLater(new Runnable() {\r
- public void run() {\r
- // Remove dialog and component listener\r
- handleRemovedDialog(dialog, true);\r
- }\r
- });\r
- }\r
- }\r
- \r
- public void eventDispatched(AWTEvent event) {\r
- assert event != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- switch (event.getID()) {\r
- case WindowEvent.WINDOW_OPENED:\r
- handleOpenedWindow((WindowEvent)event);\r
- break;\r
- \r
- case WindowEvent.WINDOW_CLOSED:\r
- handleClosedWindow((WindowEvent)event);\r
- break;\r
-\r
- case WindowEvent.WINDOW_CLOSING:\r
- handleClosingWindow((WindowEvent)event);\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
- }\r
-\r
- public void componentHidden(ComponentEvent e) {\r
- assert e != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // System.out.println("Component hidden");\r
- Object obj = e.getSource();\r
- if (obj instanceof Dialog) {\r
- // Remove dialog but keep listener in place so that we know if/when it is set visible\r
- handleRemovedDialog((Dialog)obj, false);\r
- }\r
- }\r
-\r
- public void componentShown(ComponentEvent e) {\r
- assert e != null;\r
- assert EventQueue.isDispatchThread(); // On AWT event thread\r
- \r
- // System.out.println("Component shown");\r
- Object obj = e.getSource();\r
- if (obj instanceof Dialog) {\r
- handleAddedDialog((Dialog)obj);\r
- }\r
- }\r
-\r
- public void componentResized(ComponentEvent e) {\r
- }\r
-\r
- public void componentMoved(ComponentEvent e) {\r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007 SAS Institute.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * SAS Institute - initial API and implementation
+ *******************************************************************************/
+package org.simantics.utils.ui.internal.awt;
+
+import java.awt.AWTEvent;
+import java.awt.Dialog;
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.AWTEventListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.event.WindowEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * A listener that insures the proper modal behavior of Swing dialogs when running
+ * within a SWT environment. When initialized, it blocks and unblocks SWT input
+ * as modal Swing dialogs are shown and hidden.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class AwtDialogListener implements AWTEventListener, ComponentListener {
+
+ // modalDialogs should be accessed only from the AWT thread, so no
+ // synchronization is needed.
+ private final List modalDialogs = new ArrayList();
+ private final Display display;
+
+ /**
+ * Registers this object as an AWT event listener so that Swing dialogs have the
+ * proper modal behavior in the containing SWT environment. This is called automatically
+ * when you construct a {@link EmbeddedSwingComposite}, and it
+ * need not be called separately in that case.
+ * @param shell
+ */
+ AwtDialogListener(Display display) {
+ assert display != null;
+
+ this.display = display;
+ Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.WINDOW_EVENT_MASK);
+ }
+
+ private void handleRemovedDialog(Dialog awtDialog, boolean removeListener) {
+ assert awtDialog != null;
+ assert modalDialogs != null;
+ assert display != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // System.out.println("Remove dialog: " + awtDialog);
+ if (removeListener) {
+ awtDialog.removeComponentListener(this);
+ }
+ // Note: there is no isModal() check here because the dialog might
+ // have been changed from modal to non-modal after it was opened. In this case
+ // the currently visible dialog would still act modal and we'd need to unblock
+ // SWT here when it goes away.
+ if (modalDialogs.remove(awtDialog)) {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ SwtInputBlocker.unblock();
+ }
+ });
+ }
+ }
+
+ private void handleAddedDialog(final Dialog awtDialog) {
+ assert awtDialog != null;
+ assert modalDialogs != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // System.out.println("Add dialog: " + awtDialog);
+ if (modalDialogs.contains(awtDialog) || !awtDialog.isModal() || !awtDialog.isVisible()) {
+ return;
+ }
+ modalDialogs.add(awtDialog);
+ awtDialog.addComponentListener(this);
+ display.asyncExec(new Runnable() {
+ public void run() {
+ SwtInputBlocker.block();
+ }
+ });
+ }
+
+ void requestFocus() {
+ // TODO: this does not always bring the dialog to the top
+ // under some Linux desktops/window managers (e.g. metacity under GNOME).
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ assert modalDialogs != null;
+
+ int size = modalDialogs.size();
+ if (size > 0) {
+ final Dialog awtDialog = (Dialog)modalDialogs.get(size - 1);
+
+ // In one case, a call to requestFocus() alone does not
+ // bring the AWT dialog to the top. This happens if the
+ // dialog is given a null parent frame. When opened, the dialog
+ // can be hidden by the SWT window even when it obtains focus.
+ // Calling toFront() solves the problem, but...
+ //
+ // There are still problems if the Metal look and feel is in use.
+ // The SWT window will hide the dialog the first time it is
+ // selected. Once the dialog is brought back to the front by
+ // the user, there is no further problem.
+ //
+ // Why? It looks like SWT is not being notified of lost focus when
+ // the Metal dialog first opens; subsequently, when focus is regained, the
+ // focus gain event is not posted to the SwtInputBlocker.
+ //
+ // The workaround is to use Windows look and feel, rather than Metal.
+ // System.out.println("Bringing to front");
+
+ awtDialog.requestFocus();
+ awtDialog.toFront();
+ }
+ }
+ });
+ }
+
+ private void handleOpenedWindow(WindowEvent event) {
+ assert event != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ Window window = event.getWindow();
+ if (window instanceof Dialog) {
+ handleAddedDialog((Dialog)window);
+ }
+ }
+
+ private void handleClosedWindow(WindowEvent event) {
+ assert event != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // Dispose-based close
+ Window window = event.getWindow();
+ if (window instanceof Dialog) {
+ // Remove dialog and component listener
+ handleRemovedDialog((Dialog)window, true);
+ }
+ }
+
+ private void handleClosingWindow(WindowEvent event) {
+ assert event != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // System-based close
+ Window window = event.getWindow();
+ if (window instanceof Dialog) {
+ final Dialog dialog = (Dialog) window;
+ // Defer until later. Bad things happen if
+ // handleRemovedDialog() is called directly from
+ // this event handler. The Swing dialog does not close
+ // properly and its modality remains in effect.
+ EventQueue.invokeLater(new Runnable() {
+ public void run() {
+ // Remove dialog and component listener
+ handleRemovedDialog(dialog, true);
+ }
+ });
+ }
+ }
+
+ public void eventDispatched(AWTEvent event) {
+ assert event != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ switch (event.getID()) {
+ case WindowEvent.WINDOW_OPENED:
+ handleOpenedWindow((WindowEvent)event);
+ break;
+
+ case WindowEvent.WINDOW_CLOSED:
+ handleClosedWindow((WindowEvent)event);
+ break;
+
+ case WindowEvent.WINDOW_CLOSING:
+ handleClosingWindow((WindowEvent)event);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ public void componentHidden(ComponentEvent e) {
+ assert e != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // System.out.println("Component hidden");
+ Object obj = e.getSource();
+ if (obj instanceof Dialog) {
+ // Remove dialog but keep listener in place so that we know if/when it is set visible
+ handleRemovedDialog((Dialog)obj, false);
+ }
+ }
+
+ public void componentShown(ComponentEvent e) {
+ assert e != null;
+ assert EventQueue.isDispatchThread(); // On AWT event thread
+
+ // System.out.println("Component shown");
+ Object obj = e.getSource();
+ if (obj instanceof Dialog) {
+ handleAddedDialog((Dialog)obj);
+ }
+ }
+
+ public void componentResized(ComponentEvent e) {
+ }
+
+ public void componentMoved(ComponentEvent e) {
+ }
+
+}