From 3d75736bb30623c5858fec33ad8c0a3419d35c52 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Thu, 8 Jul 2010 07:44:30 +0200 Subject: Replicate the repo... --- .../research/qtjambiawtbridge/QComponentHost.java | 149 ++++++++ .../research/qtjambiawtbridge/QWidgetHost.java | 128 +++++++ .../research/qtjambiawtbridge/QWidgetWrapper.java | 69 ++++ .../qtjambiawtbridge/QtJambiAwtBridge.java | 18 + .../qtjambiawtbridge/RedirectContainer.java | 104 ++++++ .../qtjambiawtbridge/examples/AwtInQt.java | 67 ++++ .../qtjambiawtbridge/examples/QtInAwt.java | 88 +++++ generatorstep.bat | 1 + generatorstep.sh | 1 + global.h | 5 + pregenerated/qtjambiawtbridge.jar | Bin 0 -> 33912 bytes ...olltech_research_qtjambiawtbridge_generated.dll | Bin 0 -> 77824 bytes qawt.pro | 42 +++ qcomponenthostnative.cpp | 47 +++ qcomponenthostnative.h | 33 ++ qtjambiawtbridge.cpp | 54 +++ qtwinmigrate/qmfcapp.cpp | 392 +++++++++++++++++++++ qtwinmigrate/qmfcapp.h | 58 +++ qtwinmigrate/qtwinmigrate.pri | 8 + qtwinmigrate/qwinhost.cpp | 308 ++++++++++++++++ qtwinmigrate/qwinhost.h | 57 +++ qtwinmigrate/qwinwidget.cpp | 331 +++++++++++++++++ qtwinmigrate/qwinwidget.h | 64 ++++ qwidgethostnative.cpp | 104 ++++++ qwidgethostnative.h | 34 ++ typesystem_qawt.xml | 14 + 26 files changed, 2176 insertions(+) create mode 100644 com/trolltech/research/qtjambiawtbridge/QComponentHost.java create mode 100644 com/trolltech/research/qtjambiawtbridge/QWidgetHost.java create mode 100644 com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java create mode 100644 com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java create mode 100644 com/trolltech/research/qtjambiawtbridge/RedirectContainer.java create mode 100644 com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java create mode 100644 com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java create mode 100644 generatorstep.bat create mode 100644 generatorstep.sh create mode 100644 global.h create mode 100644 pregenerated/qtjambiawtbridge.jar create mode 100644 pregenerated/win32-msvc2005/com_trolltech_research_qtjambiawtbridge_generated.dll create mode 100644 qawt.pro create mode 100644 qcomponenthostnative.cpp create mode 100644 qcomponenthostnative.h create mode 100644 qtjambiawtbridge.cpp create mode 100644 qtwinmigrate/qmfcapp.cpp create mode 100644 qtwinmigrate/qmfcapp.h create mode 100644 qtwinmigrate/qtwinmigrate.pri create mode 100644 qtwinmigrate/qwinhost.cpp create mode 100644 qtwinmigrate/qwinhost.h create mode 100644 qtwinmigrate/qwinwidget.cpp create mode 100644 qtwinmigrate/qwinwidget.h create mode 100644 qwidgethostnative.cpp create mode 100644 qwidgethostnative.h create mode 100644 typesystem_qawt.xml diff --git a/com/trolltech/research/qtjambiawtbridge/QComponentHost.java b/com/trolltech/research/qtjambiawtbridge/QComponentHost.java new file mode 100644 index 0000000..9da0640 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QComponentHost.java @@ -0,0 +1,149 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.research.qtjambiawtbridge.generated.QComponentHostNative; +import com.trolltech.qt.gui.*; +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.core.QEvent; + +import javax.swing.*; +import java.awt.*; + +public final class QComponentHost extends QComponentHostNative { + static { + Toolkit.getDefaultToolkit(); + javax.swing.UIManager.getDefaults(); + } + + private Component component; + private Frame container; + public QComponentHost(final Component hostedComponent, QWidget parent) { + super(parent); + component = hostedComponent; + setFocusPolicy(Qt.FocusPolicy.TabFocus); + } + + @Override + public void resizeEvent(QResizeEvent e) { + if (container == null) + return; + container.setBounds(0, 0, e.size().width(), e.size().height()); + } + + @Override + public boolean event(QEvent e) { + return super.event(e); + } + + @Override + protected void focusInEvent(QFocusEvent e) { + final boolean backwards = (e.reason() == Qt.FocusReason.BacktabFocusReason); + + if (!backwards && e.reason() != Qt.FocusReason.TabFocusReason) + return; + + try { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + focusAwt(backwards); + } + }); + } catch (Exception f) { + f.printStackTrace(); + } + } + + @Override + public void showEvent(QShowEvent e) { + // By trial and error, the only way to get the window handle is + // to put the component inside a Frame (which gets a window handle) + // and retrieving this in the paint method. Also, we need to make + // sure the Qt window is visible (if you attach prior to this + // then showing the window will hang indefinitely) hence we do + // this in the showEvent + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + container = RedirectContainer.embedComponent(QComponentHost.this, component); + container.setVisible(true); + } + }); + } catch (Throwable f) { f.printStackTrace(); } + } + + public QComponentHost(Component hostedComponent) { + this(hostedComponent, null); + } + + @Override + protected void closeEvent(QCloseEvent e) { + container.setVisible(false); + } + + @Override + public QSize minimumSizeHint() { + if (container == null) + return new QSize(); + + Dimension dim = container.getMinimumSize(); + return new QSize(dim.width, dim.height); + } + + @Override + public QSize sizeHint() { + if (container == null) + return new QSize(); + + Dimension d = component.getPreferredSize(); + return new QSize((int) d.getWidth(), (int) d.getHeight()); + } + + private void setFocusInQt(QWidget w, Qt.FocusReason reason) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + w.window().activateWindow(); + w.setFocus(reason); + w.update(); + } + + private void focusAwt(final boolean backwards) { + container.toFront(); + + Component c = null; + if (component instanceof Container) { + c = !backwards + ? container.getFocusTraversalPolicy().getFirstComponent((Container) component) + : container.getFocusTraversalPolicy().getLastComponent((Container) component); + } else { + c = component; + } + + if (c != null) + c.requestFocus(); + + } + + + void focusQt(final boolean backwards) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + QWidget startWidget = backwards ? QtJambiAwtBridge.previousInFocusChain(QComponentHost.this) + : nextInFocusChain(); + QWidget w = startWidget; + while (w.focusPolicy() != Qt.FocusPolicy.TabFocus + && w.focusPolicy() != Qt.FocusPolicy.StrongFocus) { + w = backwards ? QtJambiAwtBridge.previousInFocusChain(w) : w.nextInFocusChain(); + + if (w == startWidget) + break; + } + + if (w.focusPolicy() == Qt.FocusPolicy.TabFocus + || w.focusPolicy() == Qt.FocusPolicy.StrongFocus) { + w.window().setAttribute(Qt.WidgetAttribute.WA_KeyboardFocusChange, true); + setFocusInQt(w, backwards ? Qt.FocusReason.BacktabFocusReason : Qt.FocusReason.TabFocusReason); + } + } + }); + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java b/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java new file mode 100644 index 0000000..421fdb7 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QWidgetHost.java @@ -0,0 +1,128 @@ +package com.trolltech.research.qtjambiawtbridge; + +import java.awt.*; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; + +import com.trolltech.qt.core.QSize; +import com.trolltech.qt.core.Qt; +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QWidget; + +public class QWidgetHost extends Canvas { + private static final long serialVersionUID = 1L; + + private void focusQt(final boolean backwards) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + QWidget startWidget = backwards ? QtJambiAwtBridge.previousInFocusChain(QWidgetHost.this.containedWidget) + : QWidgetHost.this.containedWidget.nextInFocusChain(); + QWidget w = startWidget; + while (w.focusPolicy() != Qt.FocusPolicy.TabFocus + && w.focusPolicy() != Qt.FocusPolicy.StrongFocus) { + w = backwards ? QtJambiAwtBridge.previousInFocusChain(w) : w.nextInFocusChain(); + + if (w == startWidget) + break; + } + + if (w.focusPolicy() == Qt.FocusPolicy.TabFocus + || w.focusPolicy() == Qt.FocusPolicy.StrongFocus) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + w.window().activateWindow(); + w.window().setAttribute(Qt.WidgetAttribute.WA_KeyboardFocusChange, true); + w.setFocus(backwards ? Qt.FocusReason.BacktabFocusReason : Qt.FocusReason.TabFocusReason); + w.update(); + } + } + }); + } + + /** + * Constructs a binding layer between AWT and a QWidget. + * + * @param containedWidget This widget will become a child of the QWidgetHost on the first AWT paint event. + */ + public QWidgetHost(QWidget containedWidget) { + QApplication.setQuitOnLastWindowClosed(false); + setFocusable(true); + + childWidget = containedWidget; + sizeHint = new QSize(); + minimumSizeHint = new QSize(); + + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + if (e.getOppositeComponent() == null) { + return ; + } + + Container focusCycleRoot = getFocusCycleRootAncestor(); + boolean backwards = (e.getOppositeComponent() == focusCycleRoot.getFocusTraversalPolicy().getComponentAfter(focusCycleRoot, QWidgetHost.this)); + focusQt(backwards); + } + + }); + } + + private QWidget childWidget; + private QWidgetWrapper containedWidget; + + @Override + public void paint(Graphics g) { + if (containedWidget == null) { + setVisible(false); + QApplication.invokeAndWait(new Runnable() { + public void run() { + containedWidget = new QWidgetWrapper(childWidget, QWidgetHost.this); + sizeHint = containedWidget.sizeHint(); + minimumSizeHint = containedWidget.minimumSizeHint(); + } + }); + setVisible(true); + } + + super.paint(g); + } + + @Override + public void setBounds(final int x, final int y, final int width, final int height) { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + containedWidget.move(0, 0); + containedWidget.resize(width, height); + } + }); + } + + super.setBounds(x, y, width, height); + } + + @Override + public Dimension getPreferredSize() { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + sizeHint = containedWidget.sizeHint(); + } + }); + } + return new Dimension(sizeHint.width(), sizeHint.height()); + } + QSize sizeHint; + + @Override + public Dimension getMinimumSize() { + if (containedWidget != null) { + QApplication.invokeAndWait(new Runnable() { + public void run() { + minimumSizeHint = containedWidget.minimumSizeHint(); + } + }); + } + return new Dimension(minimumSizeHint.width(), minimumSizeHint.height()); + } + private QSize minimumSizeHint; +} diff --git a/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java b/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java new file mode 100644 index 0000000..9bcd82d --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QWidgetWrapper.java @@ -0,0 +1,69 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.research.qtjambiawtbridge.generated.QWidgetHostNative; +import com.trolltech.qt.gui.*; +import com.trolltech.qt.core.Qt; + +import javax.swing.*; +import java.awt.*; + +class QWidgetWrapper extends QWidgetHostNative { + private QWidgetHost host; + + public QWidgetWrapper(QWidget child, QWidgetHost host) { + super(host); + + // Call this to make sure the widget is connected to a native window + winId(); + + this.host = host; + child.setParent(this); + + // Make sure widget fills entire parent rect + QHBoxLayout layout = new QHBoxLayout(this); + layout.setMargin(0); + layout.setContentsMargins(0, 0, 0, 0); + layout.setSpacing(0); + layout.addWidget(child); + + setFocusPolicy(Qt.FocusPolicy.TabFocus); + setVisible(true); + } + + @Override + public void closeEvent(QCloseEvent e) { + e.setAccepted(false); + } + + private void focusAwt(final boolean backwards) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + Container c = host.getFocusCycleRootAncestor(); + + if (c != null) { + host.requestFocus(); + Component component = backwards + ? c.getFocusTraversalPolicy().getComponentBefore(c, host) + : c.getFocusTraversalPolicy().getComponentAfter(c, host); + + component.requestFocus(); + } + } + }); + } + + @Override + protected void showEvent(QShowEvent e) { + move(0, 0); + resize(host.getBounds().width, host.getBounds().height); + } + + @Override + protected synchronized void focusInEvent(QFocusEvent event) { + if (event.reason() == Qt.FocusReason.BacktabFocusReason) { + focusAwt(true); + } else if (event.reason() == Qt.FocusReason.TabFocusReason) { + focusAwt(false); + } + } +} diff --git a/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java b/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java new file mode 100644 index 0000000..943f8ff --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/QtJambiAwtBridge.java @@ -0,0 +1,18 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.qt.gui.QWidget; + +import java.awt.*; + +class QtJambiAwtBridge { + public static QWidget previousInFocusChain(QWidget w ) { + QWidget prev = null, next = w.nextInFocusChain(); + while (next != w) { + prev = next; + next = next.nextInFocusChain(); + } + return prev; + } + + static native Frame getEmbeddedFrame(long widgetNativeId); +} diff --git a/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java b/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java new file mode 100644 index 0000000..424c955 --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/RedirectContainer.java @@ -0,0 +1,104 @@ +package com.trolltech.research.qtjambiawtbridge; + +import com.trolltech.qt.gui.QWidget; +import com.trolltech.qt.gui.QApplication; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + + +// sun.awt.x11.embeddedFrame on Linux +// see text file for osx info +class RedirectContainer { + + private static class FocusComponent extends Component { + private static final long serialVersionUID = 1L; + private QComponentHost host; + + public FocusComponent(final boolean isFocusIn, final QComponentHost host) { + this.host = host; + + setFocusable(true); + setBounds(0, 0, 1, 1); + + addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + + if (e.getOppositeComponent() == null) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + return ; + } + + if (isFocusIn) { + host.focusQt(true); + } else { + host.focusQt(false); + } + } + + }); + } + + @Override + public Dimension getPreferredSize() { + return new Dimension(1, 1); + } + + @Override + public Dimension getMaximumSize() { + return new Dimension(1, 1); + } + } + + private static final long serialVersionUID = 1L; + + static Frame embedComponent(QComponentHost parent, Component component) { + Frame f = QtJambiAwtBridge.getEmbeddedFrame(parent.nativeId()); + if (f != null) { + // Connect the frame to its window handle, since it's no longer + // handled by Swing (for event processing) + f.addNotify(); + + GridBagLayout layout = new GridBagLayout(); + + f.setLayout(layout); + f.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy()); + f.setFocusTraversalPolicyProvider(true); + + GridBagConstraints focusConstraints = new GridBagConstraints(); + focusConstraints.ipadx = 0; + focusConstraints.ipady = 0; + focusConstraints.anchor = GridBagConstraints.CENTER; + focusConstraints.fill = GridBagConstraints.NONE; + focusConstraints.insets.left = 0; + focusConstraints.insets.right = 0; + focusConstraints.insets.bottom = 0; + focusConstraints.insets.top = 0; + + FocusComponent focusIn = new FocusComponent(true, parent); + + layout.setConstraints(focusIn, focusConstraints); + f.add(focusIn); + + { + GridBagConstraints constraints = (GridBagConstraints) focusConstraints.clone(); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 1; + constraints.weighty = 1; + + f.add(component); + } + + FocusComponent focusOut = new FocusComponent(false, parent); + layout.setConstraints(focusOut, focusConstraints); + f.add(focusOut); + + f.pack(); + } + + return f; + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java b/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java new file mode 100644 index 0000000..6a2f2eb --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/examples/AwtInQt.java @@ -0,0 +1,67 @@ +package com.trolltech.research.qtjambiawtbridge.examples; + +import com.trolltech.qt.gui.*; +import com.trolltech.research.qtjambiawtbridge.QComponentHost; + +import javax.swing.*; +import java.awt.*; + +public class AwtInQt extends QWidget { + + public AwtInQt() { + QGridLayout layout = new QGridLayout(this); + + // A few Qt widgets + layout.addWidget(new QLabel("First name:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + layout.addWidget(new QLabel("Last name:"), 1, 0); + layout.addWidget(new QLineEdit(), 1, 1); + + // The AWT part of the GUI + { + JPanel panel = new JPanel(); + + panel.setLayout(new GridLayout(1, 2)); + + panel.add(new JLabel("Social security number:")); + panel.add(new JTextField()); + + // Add the AWT panel to Qt's layout + layout.addWidget(new QComponentHost(panel), 2, 0, 1, 2); + } + + { + JPanel panel = new JPanel(); + + panel.setLayout(new GridLayout(2, 4)); + + panel.add(new JLabel("Phone number:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Address:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Credit card #:")); + panel.add(new JTextField()); + + panel.add(new JLabel("Expiration date:")); + panel.add(new JTextField()); + + // Add the AWT panel to Qt's layout + layout.addWidget(new QComponentHost(panel), 4, 0, 1, 2); + } + + } + + public static void main(String[] args) { + QApplication.initialize(args); + + AwtInQt awtInQt = new AwtInQt(); + awtInQt.show(); + + QApplication.exec(); + + System.exit(0); + } + +} diff --git a/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java b/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java new file mode 100644 index 0000000..bef356e --- /dev/null +++ b/com/trolltech/research/qtjambiawtbridge/examples/QtInAwt.java @@ -0,0 +1,88 @@ +package com.trolltech.research.qtjambiawtbridge.examples; + +import java.awt.GridLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +import com.trolltech.qt.gui.QApplication; +import com.trolltech.qt.gui.QGridLayout; +import com.trolltech.qt.gui.QLabel; +import com.trolltech.qt.gui.QLineEdit; +import com.trolltech.qt.gui.QWidget; +import com.trolltech.research.qtjambiawtbridge.QWidgetHost; + +public class QtInAwt extends JFrame { + + private static final long serialVersionUID = 1L; + + public QtInAwt() { + setLayout(new GridLayout(4, 1)); + + { + JPanel row = new JPanel(); + row.setLayout(new GridLayout(1, 2)); + row.add(new JLabel("First name:")); + row.add(new JTextField()); + + add(row); + } + + { + JPanel row = new JPanel(); + row.setLayout(new GridLayout(1, 2)); + row.add(new JLabel("Last name:")); + row.add(new JTextField()); + + add(row); + } + + // The Qt part of the GUI + { + QWidget row = new QWidget(); + QGridLayout layout = new QGridLayout(row); + layout.addWidget(new QLabel("Social security number:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + + // Add the Qt widget to AWT's layout + add(new QWidgetHost(row)); + } + + { + QWidget row = new QWidget(); + QGridLayout layout = new QGridLayout(row); + layout.addWidget(new QLabel("Phone number:"), 0, 0); + layout.addWidget(new QLineEdit(), 0, 1); + + layout.addWidget(new QLabel("Address:"), 1, 0); + layout.addWidget(new QLineEdit(), 1, 1); + + layout.addWidget(new QLabel("Credit card #:"), 0, 2); + layout.addWidget(new QLineEdit(), 0, 3); + + layout.addWidget(new QLabel("Expiration date:"), 1, 2); + layout.addWidget(new QLineEdit(), 1, 3); + + // Add the Qt widget to AWT's layout + add(new QWidgetHost(row)); + } + + } + + public static void main(String args[]) { + // We have to initialize Qt Jambi in order to use its widgets + QApplication.initialize(args); + + QtInAwt qtInAwt = new QtInAwt(); + qtInAwt.setVisible(true); + qtInAwt.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + qtInAwt.setSize(640, 480); + + // We need to run a Qt Jambi event loop in this thread in order + // for its widgets to receive events + QApplication.exec(); + } + +} diff --git a/generatorstep.bat b/generatorstep.bat new file mode 100644 index 0000000..75cd96c --- /dev/null +++ b/generatorstep.bat @@ -0,0 +1 @@ +%JAMBIDIR%\generator\release\generator --include-paths=%CD%\qtwinmigrate global.h typesystem_qawt.xml diff --git a/generatorstep.sh b/generatorstep.sh new file mode 100644 index 0000000..533fc94 --- /dev/null +++ b/generatorstep.sh @@ -0,0 +1 @@ +$JAMBIDIR/generator/generator global.h typesystem_qawt.xml diff --git a/global.h b/global.h new file mode 100644 index 0000000..7ec5a4c --- /dev/null +++ b/global.h @@ -0,0 +1,5 @@ +#include +#include + +#include "qcomponenthostnative.h" +#include "qwidgethostnative.h" diff --git a/pregenerated/qtjambiawtbridge.jar b/pregenerated/qtjambiawtbridge.jar new file mode 100644 index 0000000..79dbf10 Binary files /dev/null and b/pregenerated/qtjambiawtbridge.jar differ diff --git a/pregenerated/win32-msvc2005/com_trolltech_research_qtjambiawtbridge_generated.dll b/pregenerated/win32-msvc2005/com_trolltech_research_qtjambiawtbridge_generated.dll new file mode 100644 index 0000000..79592b0 Binary files /dev/null and b/pregenerated/win32-msvc2005/com_trolltech_research_qtjambiawtbridge_generated.dll differ diff --git a/qawt.pro b/qawt.pro new file mode 100644 index 0000000..138bb55 --- /dev/null +++ b/qawt.pro @@ -0,0 +1,42 @@ +!exists($(JAVADIR)) { + error("Please set your JAVADIR environment variable to point to your local JDK..") ; +} + +TARGET = com_trolltech_research_qtjambiawtbridge_generated + + +QTJAMBI_LOCATION_TMP=$$(JAMBIDIR) +isEmpty(QTJAMBI_LOCATION_TMP) { + error("Please specify the JAMBIDIR environment variable."); +} + +!exists($$(JAMBIDIR)/qtjambi/qtjambi_include.pri) { + error("$JAMBIDIR/qtjambi/qtjambi_include.pri was not found!"); +} + + + +SOURCES += qtjambiawtbridge.cpp qwidgethostnative.cpp qcomponenthostnative.cpp +HEADERS += qwidgethostnative.h qcomponenthostnative.h + +include($$(JAMBIDIR)/qtjambi/qtjambi_include.pri) +include(cpp/com_trolltech_research_qtjambiawtbridge_generated/com_trolltech_research_qtjambiawtbridge_generated.pri) + + + +DESTDIR = ./lib +DLLDESTDIR= ./bin + +win*{ + INCLUDEPATH += $$PWD/qtwinmigrate + LIBS += "$$(JAVADIR)/lib/jawt.lib" + include(qtwinmigrate/qtwinmigrate.pri) +} else { + INCLUDEPATH += $$PWD/linux + LIBPATH += $$JAVADIR/lib + LIBS += -ljawt +} + +win32: LIBS += -lgdi32 -luser32 + +LIBPATH += $$(JAVADIR)/jre/lib/i386 diff --git a/qcomponenthostnative.cpp b/qcomponenthostnative.cpp new file mode 100644 index 0000000..5b471d3 --- /dev/null +++ b/qcomponenthostnative.cpp @@ -0,0 +1,47 @@ +#include "qcomponenthostnative.h" + +QComponentHostNative::QComponentHostNative(QWidget *parent) + : QCOMPONENTHOSTNATIVE_BASECLASS(parent) +{ +} + +// ### Empty implementations to work around limitation in generator +void QComponentHostNative::childEvent(QChildEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::childEvent(e); +} + +bool QComponentHostNative::eventFilter(QObject *o, QEvent *e) +{ + return QCOMPONENTHOSTNATIVE_BASECLASS::eventFilter(o, e); +} + +void QComponentHostNative::focusInEvent(QFocusEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::focusInEvent(e); +} + +void QComponentHostNative::paintEvent(QPaintEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::paintEvent(e); +} + +void QComponentHostNative::resizeEvent(QResizeEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::resizeEvent(e); +} + +void QComponentHostNative::showEvent(QShowEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::showEvent(e); +} + +void QComponentHostNative::hideEvent(QHideEvent *e) +{ + QCOMPONENTHOSTNATIVE_BASECLASS::hideEvent(e); +} + +bool QComponentHostNative::event(QEvent *e) +{ + return QCOMPONENTHOSTNATIVE_BASECLASS::event(e); +} diff --git a/qcomponenthostnative.h b/qcomponenthostnative.h new file mode 100644 index 0000000..c726f5b --- /dev/null +++ b/qcomponenthostnative.h @@ -0,0 +1,33 @@ +#ifndef QCOMPONENTHOSTNATIVE_H +#define QCOMPONENTHOSTNATIVE_H + +#include + +#if defined(QT_JAMBI_RUN) +# define QCOMPONENTHOSTNATIVE_BASECLASS QWidget +#elif defined(Q_OS_WIN32) +# include "qwinhost.h" +# define QCOMPONENTHOSTNATIVE_BASECLASS QWinHost +#else +# include +# define QCOMPONENTHOSTNATIVE_BASECLASS QX11EmbedContainer +#endif + +class QComponentHostNative: public QCOMPONENTHOSTNATIVE_BASECLASS +{ +public: + QComponentHostNative(QWidget *parent = 0); + +protected: + void childEvent(QChildEvent *e); + bool eventFilter(QObject *o, QEvent *e); + void focusInEvent(QFocusEvent *e); + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *e); + void showEvent(QShowEvent *e); + void hideEvent(QHideEvent *e); + bool event(QEvent *e); + +}; + +#endif diff --git a/qtjambiawtbridge.cpp b/qtjambiawtbridge.cpp new file mode 100644 index 0000000..3f3bb81 --- /dev/null +++ b/qtjambiawtbridge.cpp @@ -0,0 +1,54 @@ +#include + +#include + +#include + +const char *qtjambi_awt_title = "Qt Jambi / AWT"; + +extern "C" JNIEXPORT jobject JNICALL Java_com_trolltech_research_qtjambiawtbridge_QtJambiAwtBridge_getEmbeddedFrame +(JNIEnv *env, jclass, jlong widgetNativeId) +{ +#ifdef Q_OS_WIN32 + const char *embeddedFramePackageName = "sun/awt/windows/"; + const char *embeddedFrameClassName = "WEmbeddedFrame"; +#else + const char *embeddedFramePackageName = "sun/awt/X11/"; + const char *embeddedFrameClassName = "XEmbeddedFrame"; +#endif + + QWidget *widget = reinterpret_cast(qtjambi_from_jlong(widgetNativeId)); + if (widget == 0) { + qWarning("%s [%s:%d]: Component host widget has been deleted\n", qtjambi_awt_title, __FILE__, __LINE__); + return 0; + } + + jclass embeddedFrameClass = resolveClass(env, embeddedFrameClassName, embeddedFramePackageName); + if (embeddedFrameClass == 0) { + qWarning("%s [%s:%d]: Embedded frame class '%s%s' not found\n", + qtjambi_awt_title, __FILE__, __LINE__, embeddedFramePackageName, embeddedFrameClassName); + return 0; + } + + jmethodID constructor = resolveMethod(env, "", "(I)V", + embeddedFrameClassName, + embeddedFramePackageName); + // Different constructors on different JREs. + if (constructor == 0) { + env->ExceptionClear(); + constructor = resolveMethod(env, "", "(J)V", + embeddedFrameClassName, + embeddedFramePackageName); + } + + if (constructor == 0) { + qWarning("%s [%s:%d]: Cannot find constructor in embedded frame class\n", qtjambi_awt_title, __FILE__, __LINE__); + return 0; + } + + WId windowId = widget->winId(); + + return env->NewObject(embeddedFrameClass, constructor, windowId); +} + + diff --git a/qtwinmigrate/qmfcapp.cpp b/qtwinmigrate/qmfcapp.cpp new file mode 100644 index 0000000..79d68f2 --- /dev/null +++ b/qtwinmigrate/qmfcapp.cpp @@ -0,0 +1,392 @@ +// Implementation of the QMfcApp classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#ifdef UNICODE +#undef UNICODE +#endif + +#include "qmfcapp.h" + +#include +#include +#include + +#ifdef QTWINMIGRATE_WITHMFC +#include +#else +#include +#endif + +#ifdef QTWINMIGRATE_WITHMFC +CWinApp *QMfcApp::mfc_app = 0; +char **QMfcApp::mfc_argv = 0; +int QMfcApp::mfc_argc = 0; +#endif + +/*! \class QMfcApp qmfcapp.h + \brief The QMfcApp class provides merging of the MFC and Qt event loops. + + QMfcApp is responsible for driving both the Qt and MFC event loop. + It replaces the standard MFC event loop provided by + CWinApp::Run(), and is used instead of the QApplication parent + class. + + To replace the MFC event loop reimplement the CWinApp::Run() + function in the CWinApp subclass usually created by the MFC + Application Wizard, and use either the static run() function, or + an instance of QMfcApp created earlier through the static + instance() function or the constructor. + + The QMfcApp class also provides a static API pluginInstance() that + drives the Qt event loop when loaded into an MFC or Win32 application. + This is useful for developing Qt based DLLs or plugins, or if the + MFC application's event handling can not be modified. +*/ + +static int modalLoopCount = 0; + +HHOOK hhook; +LRESULT CALLBACK QtFilterProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + if (qApp) { + // don't process deferred-deletes while in a modal loop + if (modalLoopCount) + qApp->sendPostedEvents(); + else + qApp->sendPostedEvents(0, -1); + } + + return CallNextHookEx(hhook, nCode, wParam, lParam); +} + +/*! + Inform Qt that a modal loop is about to be entered, and that DeferredDelete + events should not be processed. Call this function before calling Win32 + or MFC functions that enter a modal event loop (i.e. MessageBox). + + This is only required if the Qt UI code hooks into an existing Win32 + event loop using QMfcApp::pluginInstance. + + \sa exitModalLoop() +*/ +void QMfcApp::enterModalLoop() +{ + ++modalLoopCount; +} + +/*! + Inform Qt that a modal loop has been exited, and that DeferredDelete + events should not be processed. Call this function after the blocking + Win32 or MFC function (i.e. MessageBox) returned. + + This is only required if the Qt UI code hooks into an existing Win32 + event loop using QMfcApp::pluginInstance. + + \sa enterModalLoop() +*/ +void QMfcApp::exitModalLoop() +{ + --modalLoopCount; + Q_ASSERT(modalLoopCount >= 0); +} + +/*! + If there is no global QApplication object (i.e. qApp is null) this + function creates a QApplication instance and returns true; + otherwise it does nothing and returns false. + + The application installs an event filter that drives the Qt event + loop while the MFC or Win32 application continues to own the event + loop. + + Use this static function if the application event loop code can not be + easily modified, or when developing a plugin or DLL that will be loaded + into an existing Win32 or MFC application. If \a plugin is non-null then + the function loads the respective DLL explicitly to avoid unloading from + memory. + + \code + BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpvReserved) + { + if (dwReason == DLL_PROCESS_ATTACH) + QMfcApp::pluginInstance(hInstance); + + return TRUE; + } + \endcode + + Set \a plugin to 0 when calling this function from within the same executable + module. + + If this function is used, call enterModalLoop and exitModalLoop whenever you + call a Win32 or MFC function that opens a local event loop. + + \code + void Dialog::someSlot() + { + QMfcApp::enterModalLoop(); + MessageBox(...); + QMfcApp::exitModalLoop(); + } + \endcode +*/ +bool QMfcApp::pluginInstance(Qt::HANDLE plugin) +{ + if (qApp) + return FALSE; + + QT_WA({ + hhook = SetWindowsHookExW(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); + }, { + hhook = SetWindowsHookExA(WH_GETMESSAGE, QtFilterProc, 0, GetCurrentThreadId()); + }); + + int argc = 0; + (void)new QApplication(argc, 0); + + if (plugin) { + char filename[256]; + if (GetModuleFileNameA((HINSTANCE)plugin, filename, 255)) + LoadLibraryA(filename); + } + + return TRUE; +} + +#ifdef QTWINMIGRATE_WITHMFC +/*! + Runs the event loop for both Qt and the MFC application object \a + mfcApp, and returns the result. This function calls \c instance() + if no QApplication object exists and deletes the object it + created. + + Calling this static function in a reimplementation of + CWinApp::Run() is the simpliest way to use the QMfcApp class: + + \code + int MyMfcApp::Run() + { + return QMfcApp::run(this); + } + \endcode + + Since a QApplication object must exist before Qt widgets can be + created you cannot use this function if you want to use Qt-based + user interface elements in, for example, the InitInstance() + function of CWinApp. In such cases, create an instance of + QApplication explicitly using instance() or the constructor. + + \sa instance() +*/ +int QMfcApp::run(CWinApp *mfcApp) +{ + bool ownInstance = !qApp; + if (ownInstance) + instance(mfcApp); + int result = qApp->exec(); + + if (mfcApp) { + int mfcRes = mfcApp->ExitInstance(); + if (mfcRes && !result) + result = mfcRes; + } + + if (ownInstance) + delete qApp; + + return result; +} + +/*! + Creates an instance of QApplication, passing the command line of + \a mfcApp to the QApplication constructor, and returns the new + object. The returned object must be destroyed by the caller. + + Use this static function if you want to perform additional + initializations after creating the application object, or if you + want to create Qt GUI elements in the InitInstance() + reimplementation of CWinApp: + + \code + BOOL MyMfcApp::InitInstance() + { + // standard MFC initialization + // ... + + // This sets the global qApp pointer + QMfcApp::instance(this); + + // Qt GUI initialization + } + + BOOL MyMfcApp::Run() + { + int result = QMfcApp::run(this); + delete qApp; + return result; + } + \endcode + + \sa run() +*/ +QApplication *QMfcApp::instance(CWinApp *mfcApp) +{ + mfc_app = mfcApp; + if (mfc_app) { +#if defined(UNICODE) + QString exeName((QChar*)mfc_app->m_pszExeName, wcslen(mfc_app->m_pszExeName)); + QString cmdLine((QChar*)mfc_app->m_lpCmdLine, wcslen(mfc_app->m_lpCmdLine)); +#else + QString exeName = QString::fromLocal8Bit(mfc_app->m_pszExeName); + QString cmdLine = QString::fromLocal8Bit(mfc_app->m_lpCmdLine); +#endif + QStringList arglist = QString(exeName + " " + cmdLine).split(' '); + + mfc_argc = arglist.count(); + mfc_argv = new char*[mfc_argc+1]; + int a; + for (a = 0; a < mfc_argc; ++a) { + QString arg = arglist[a]; + mfc_argv[a] = new char[arg.length()+1]; + qstrcpy(mfc_argv[a], arg.toLocal8Bit().data()); + } + mfc_argv[a] = 0; + } + + return new QMfcApp(mfcApp, mfc_argc, mfc_argv); +} + + +static bool qmfc_eventFilter(void *message) +{ + long result = 0; + return static_cast(qApp)->winEventFilter((MSG*)message, &result); +} + +/*! + Creates an instance of QMfcApp. \a mfcApp must point to the + existing instance of CWinApp. \a argc and \a argv are passed on + to the QApplication constructor. + + Use the static function instance() to automatically use the + command line passed to the CWinApp. + + \code + QMfcApp *qtApp; + + BOOL MyMfcApp::InitInstance() + { + // standard MFC initialization + + int argc = ... + char **argv = ... + + qtApp = new QMfcApp(this, argc, argv); + + // Qt GUI initialization + } + + BOOL MyMfcApp::Run() + { + int result = qtApp->exec(); + delete qtApp; + qtApp = 0; + + return result; + } + \endcode + + \sa instance() run() +*/ +QMfcApp::QMfcApp(CWinApp *mfcApp, int &argc, char **argv) +: QApplication(argc, argv), idleCount(0), doIdle(FALSE) +{ + mfc_app = mfcApp; + QAbstractEventDispatcher::instance()->setEventFilter(qmfc_eventFilter); + setQuitOnLastWindowClosed(false); +} +#endif + +/*! + Destroys the QMfcApp object, freeing all allocated resources. +*/ +QMfcApp::~QMfcApp() +{ + if (hhook) { + UnhookWindowsHookEx(hhook); + hhook = 0; + } + +#ifdef QTWINMIGRATE_WITHMFC + for (int a = 0; a < mfc_argc; ++a) { + char *arg = mfc_argv[a]; + delete[] arg; + } + delete []mfc_argv; + + mfc_argc = 0; + mfc_argv = 0; + mfc_app = 0; +#endif +} + +/*! + \reimp +*/ +bool QMfcApp::winEventFilter(MSG *msg, long *result) +{ + static bool recursion = false; + if (recursion) + return false; + + recursion = true; + + QWidget *widget = QWidget::find(msg->hwnd); + HWND toplevel = 0; + if (widget) { + HWND parent = widget->winId(); + while(parent) { + toplevel = parent; + parent = GetParent(parent); + } + HMENU menu = toplevel ? GetMenu(toplevel) : 0; + if (menu && GetFocus() == msg->hwnd) { + if (msg->message == WM_SYSKEYUP && msg->wParam == VK_MENU) { + // activate menubar on Alt-up and move focus away + SetFocus(toplevel); + SendMessage(toplevel, msg->message, msg->wParam, msg->lParam); + widget->setFocus(); + recursion = false; + return TRUE; + } else if (msg->message == WM_SYSKEYDOWN && msg->wParam != VK_MENU) { + SendMessage(toplevel, msg->message, msg->wParam, msg->lParam); + SendMessage(toplevel, WM_SYSKEYUP, VK_MENU, msg->lParam); + recursion = false; + return TRUE; + } + } + } +#ifdef QTWINMIGRATE_WITHMFC + else if (mfc_app) { + MSG tmp; + while (doIdle && !PeekMessage(&tmp, 0, 0, 0, PM_NOREMOVE)) { + if (!mfc_app->OnIdle(idleCount++)) + doIdle = FALSE; + } + if (mfc_app->IsIdleMessage(msg)) { + doIdle = TRUE; + idleCount = 0; + } + } + if (mfc_app && mfc_app->PreTranslateMessage(msg)) { + recursion = false; + return TRUE; + } +#endif + + recursion = false; + return QApplication::winEventFilter(msg, result); +} diff --git a/qtwinmigrate/qmfcapp.h b/qtwinmigrate/qmfcapp.h new file mode 100644 index 0000000..7a3f5ca --- /dev/null +++ b/qtwinmigrate/qmfcapp.h @@ -0,0 +1,58 @@ + +// Declaration of the QMfcApp classes + +#ifndef QMFCAPP_H +#define QMFCAPP_H + +#include + +#if defined(_AFXDLL) && defined(_MSC_VER) +#define QTWINMIGRATE_WITHMFC +class CWinApp; +#endif + +#if defined(Q_WS_WIN) +# if !defined(QT_QTWINMIGRATE_EXPORT) && !defined(QT_QTWINMIGRATE_IMPORT) +# define QT_QTWINMIGRATE_EXPORT +# elif defined(QT_QTWINMIGRATE_IMPORT) +# if defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# endif +# define QT_QTWINMIGRATE_EXPORT __declspec(dllimport) +# elif defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# define QT_QTWINMIGRATE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTWINMIGRATE_EXPORT +#endif + +class QT_QTWINMIGRATE_EXPORT QMfcApp : public QApplication +{ +public: + static bool pluginInstance(Qt::HANDLE plugin = 0); + +#ifdef QTWINMIGRATE_WITHMFC + static int run(CWinApp *mfcApp); + static QApplication *instance(CWinApp *mfcApp); + QMfcApp(CWinApp *mfcApp, int &argc, char **argv); +#endif + ~QMfcApp(); + + bool winEventFilter(MSG *msg, long *result); + + static void enterModalLoop(); + static void exitModalLoop(); + +private: +#ifdef QTWINMIGRATE_WITHMFC + static char ** mfc_argv; + static int mfc_argc; + static CWinApp *mfc_app; +#endif + + int idleCount; + bool doIdle; +}; + +#endif // QMFCAPP_H diff --git a/qtwinmigrate/qtwinmigrate.pri b/qtwinmigrate/qtwinmigrate.pri new file mode 100644 index 0000000..b57a866 --- /dev/null +++ b/qtwinmigrate/qtwinmigrate.pri @@ -0,0 +1,8 @@ +HEADERS += $$PWD/qwinhost.h \ + $$PWD/qwinwidget.h \ + $$PWD/qmfcapp.h + +SOURCES += $$PWD/qwinhost.cpp \ + $$PWD/qwinwidget.cpp \ + $$PWD/qmfcapp.cpp + diff --git a/qtwinmigrate/qwinhost.cpp b/qtwinmigrate/qwinhost.cpp new file mode 100644 index 0000000..a8028b9 --- /dev/null +++ b/qtwinmigrate/qwinhost.cpp @@ -0,0 +1,308 @@ +// Implementation of the QWinHost classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#include "qwinhost.h" + +#include +#include + +/*! + \class QWinHost qwinhost.h + \brief The QWinHost class provides an API to use native Win32 + windows in Qt applications. + + QWinHost exists to provide a QWidget that can act as a parent for + any native Win32 control. Since QWinHost is a proper QWidget, it + can be used as a toplevel widget (e.g. 0 parent) or as a child of + any other QWidget. + + QWinHost integrates the native control into the Qt user interface, + e.g. handles focus switches and laying out. + + Applications moving to Qt may have custom Win32 controls that will + take time to rewrite with Qt. Such applications can use these + custom controls as children of QWinHost widgets. This allows the + application's user interface to be replaced gradually. + + When the QWinHost is destroyed, and the Win32 window hasn't been + set with setWindow(), the window will also be destroyed. +*/ + +/*! + Creates an instance of QWinHost. \a parent and \a f are + passed on to the QWidget constructor. The widget has by default + no background. + + \warning You cannot change the parent widget of the QWinHost instance + after the native window has been created, i.e. do not call + QWidget::setParent or move the QWinHost into a different layout. +*/ +QWinHost::QWinHost(QWidget *parent, Qt::WFlags f) +: QWidget(parent, f), wndproc(0),own_hwnd(false), hwnd(0), m_hook(0) +{ + setAttribute(Qt::WA_NoBackground); + setAttribute(Qt::WA_NoSystemBackground); +} + +/*! + Destroys the QWinHost object. If the hosted Win32 window has not + been set explicitly using setWindow() the window will be + destroyed. +*/ +QWinHost::~QWinHost() +{ + if (wndproc) { +#if defined(GWLP_WNDPROC) + QT_WA({ + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc); + },{ + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)wndproc); + }) +#else + QT_WA({ + SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wndproc); + },{ + SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)wndproc); + }) +#endif + } + + if (hwnd && own_hwnd) + DestroyWindow(hwnd); +} + +/*! + Reimplement this virtual function to create and return the native + Win32 window. \a parent is the handle to this widget, and \a + instance is the handle to the application instance. The returned HWND + must be a child of the \a parent HWND. + + The default implementation returns null. The window returned by a + reimplementation of this function is owned by this QWinHost + instance and will be destroyed in the destructor. + + This function is called by the implementation of polish() if no + window has been set explicitly using setWindow(). Call polish() to + force this function to be called. + + \sa setWindow() +*/ +HWND QWinHost::createWindow(HWND parent, HINSTANCE instance) +{ + Q_UNUSED(parent); + Q_UNUSED(instance); + return 0; +} + +/*! + Ensures that the window provided a child of this widget, unless + it is a WS_OVERLAPPED window. +*/ +void QWinHost::fixParent() +{ + if (!hwnd) + return; + if (!::IsWindow(hwnd)) { + hwnd = 0; + return; + } + if (::GetParent(hwnd) == winId()) + return; + long style = GetWindowLong(hwnd, GWL_STYLE); + if (style & WS_OVERLAPPED) + return; + ::SetParent(hwnd, winId()); +} + +/*! + Sets the native Win32 window to \a window. If \a window is not a child + window of this widget, then it is reparented to become one. If \a window + is not a child window (i.e. WS_OVERLAPPED is set), then this function does nothing. + + The lifetime of the window handle will be managed by Windows, QWinHost does not + call DestroyWindow. To verify that the handle is destroyed when expected, handle + WM_DESTROY in the window procedure. + + \sa window(), createWindow() +*/ +void QWinHost::setWindow(HWND window) +{ + if (hwnd && own_hwnd) + DestroyWindow(hwnd); + + hwnd = window; + fixParent(); + + own_hwnd = false; +} + +/*! + Returns the handle to the native Win32 window, or null if no + window has been set or created yet. + + \sa setWindow(), createWindow() +*/ +HWND QWinHost::window() const +{ + return hwnd; +} + +void *getWindowProc(QWinHost *host) +{ + return host ? host->wndproc : 0; +} + +LRESULT CALLBACK WinHostProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + QWinHost *widget = qobject_cast(QWidget::find(::GetParent(hwnd))); + WNDPROC oldproc = (WNDPROC)getWindowProc(widget); + if (widget) { + switch(msg) { + case WM_LBUTTONDOWN: + if (::GetFocus() != hwnd && (widget->focusPolicy() & Qt::ClickFocus)) { + widget->setFocus(Qt::MouseFocusReason); + } + break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + QT_WA({ + SendMessage(widget->winId(), msg, wParam, lParam); + }, { + SendMessageA(widget->winId(), msg, wParam, lParam); + }) + break; + + case WM_KEYDOWN: + if (wParam == VK_TAB) { + QT_WA({ + SendMessage(widget->winId(), msg, wParam, lParam); + }, { + SendMessageA(widget->winId(), msg, wParam, lParam); + }) + } + break; + + default: + break; + } + } + + QT_WA({ + if (oldproc) + return CallWindowProc(oldproc, hwnd, msg, wParam, lParam); + return DefWindowProc(hwnd,msg,wParam,lParam); + }, { + if (oldproc) + return CallWindowProcA(oldproc, hwnd, msg, wParam, lParam); + return DefWindowProcA(hwnd,msg,wParam,lParam); + }) +} + +/*! + \reimp +*/ +bool QWinHost::event(QEvent *e) +{ + switch(e->type()) { + case QEvent::Polish: + if (!hwnd) { + hwnd = createWindow(winId(), qWinAppInst()); + fixParent(); + own_hwnd = hwnd != 0; + } + if (hwnd && !wndproc && GetParent(hwnd) == winId()) { +#if defined(GWLP_WNDPROC) + QT_WA({ + wndproc = (void*)GetWindowLongPtr(hwnd, GWLP_WNDPROC); + SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc); + }, { + wndproc = (void*)GetWindowLongPtrA(hwnd, GWLP_WNDPROC); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)WinHostProc); + }) +#else + QT_WA({ + wndproc = (void*)GetWindowLong(hwnd, GWL_WNDPROC); + SetWindowLong(hwnd, GWL_WNDPROC, (LONG)WinHostProc); + }, { + wndproc = (void*)GetWindowLongA(hwnd, GWL_WNDPROC); + SetWindowLongA(hwnd, GWL_WNDPROC, (LONG)WinHostProc); + }) +#endif + + LONG style; + QT_WA({ + style = GetWindowLong(hwnd, GWL_STYLE); + }, { + style = GetWindowLongA(hwnd, GWL_STYLE); + }) + if (style & WS_TABSTOP) + setFocusPolicy(Qt::FocusPolicy(focusPolicy() | Qt::StrongFocus)); + } + break; + case QEvent::WindowBlocked: + if (hwnd) + EnableWindow(hwnd, false); + break; + case QEvent::WindowUnblocked: + if (hwnd) + EnableWindow(hwnd, true); + break; + } + return QWidget::event(e); +} + +/*! + \reimp +*/ +void QWinHost::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + + if (hwnd) + SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), SWP_SHOWWINDOW); +} + +/*! + \reimp +*/ +void QWinHost::focusInEvent(QFocusEvent *e) +{ + QWidget::focusInEvent(e); + + if (hwnd) + ::SetFocus(hwnd); +} + +/*! + \reimp +*/ +void QWinHost::resizeEvent(QResizeEvent *e) +{ + QWidget::resizeEvent(e); + + if (hwnd) + SetWindowPos(hwnd, HWND_TOP, 0, 0, width(), height(), 0); +} + +/*! + \reimp +*/ +bool QWinHost::winEvent(MSG *msg, long *result) +{ + switch (msg->message) + { + case WM_SETFOCUS: + if (hwnd) { + ::SetFocus(hwnd); + return true; + } + default: + break; + } + + return QWidget::winEvent(msg, result); +} diff --git a/qtwinmigrate/qwinhost.h b/qtwinmigrate/qwinhost.h new file mode 100644 index 0000000..bf8686e --- /dev/null +++ b/qtwinmigrate/qwinhost.h @@ -0,0 +1,57 @@ + +// Declaration of the QWinHost classes + +#ifndef QWINHOST_H +#define QWINHOST_H + +#include + +#if defined(Q_WS_WIN) +# if !defined(QT_QTWINMIGRATE_EXPORT) && !defined(QT_QTWINMIGRATE_IMPORT) +# define QT_QTWINMIGRATE_EXPORT +# elif defined(QT_QTWINMIGRATE_IMPORT) +# if defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# endif +# define QT_QTWINMIGRATE_EXPORT __declspec(dllimport) +# elif defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# define QT_QTWINMIGRATE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTWINMIGRATE_EXPORT +#endif + +#include + +class QT_QTWINMIGRATE_EXPORT QWinHost : public QWidget +{ + Q_OBJECT +public: + QWinHost(QWidget *parent = 0, Qt::WFlags f = 0); + ~QWinHost(); + + void setWindow(HWND); + HWND window() const; + +protected: + virtual HWND createWindow(HWND parent, HINSTANCE instance); + + bool event(QEvent *e); + void showEvent(QShowEvent *); + void focusInEvent(QFocusEvent*); + void resizeEvent(QResizeEvent*); + + bool winEvent(MSG *msg, long *result); + +private: + void fixParent(); + friend void* getWindowProc(QWinHost*); + + void *wndproc; + bool own_hwnd; + HHOOK m_hook; + HWND hwnd; +}; + +#endif // QWINHOST_H diff --git a/qtwinmigrate/qwinwidget.cpp b/qtwinmigrate/qwinwidget.cpp new file mode 100644 index 0000000..2c0929f --- /dev/null +++ b/qtwinmigrate/qwinwidget.cpp @@ -0,0 +1,331 @@ +// Implementation of the QWinWidget classes + +#ifdef QT3_SUPPORT +#undef QT3_SUPPORT +#endif + +#ifdef UNICODE +#undef UNICODE +#endif + +#include "qmfcapp.h" + +#ifdef QTWINMIGRATE_WITHMFC +#include +#endif + +#include + +#include "qwinwidget.h" + +#include + +/*! + \class QWinWidget qwinwidget.h + \brief The QWinWidget class is a Qt widget that can be child of a + native Win32 widget. + + The QWinWidget class is the bridge between an existing application + user interface developed using native Win32 APIs or toolkits like + MFC, and Qt based GUI elements. + + Using QWinWidget as the parent of QDialogs will ensure that + modality, placement and stacking works properly throughout the + entire application. If the child widget is a top level window that + uses the \c WDestructiveClose flag, QWinWidget will destroy itself + when the child window closes down. + + Applications moving to Qt can use QWinWidget to add new + functionality, and gradually replace the existing interface. +*/ + +/*! + Creates an instance of QWinWidget. \a hParentWnd is the handle to + the native Win32 parent. If a \a parent is provided the object is + owned by that QObject. \a f is passed on to the QWidget constructor. +*/ +QWinWidget::QWinWidget(HWND hParentWnd, QObject *parent, Qt::WFlags f) +: QWidget(0, f), hParent(hParentWnd), prevFocus(0), reenable_parent(false) +{ + if (parent) + QObject::setParent(parent); + + init(); +} + +#ifdef QTWINMIGRATE_WITHMFC +/*! + \overload + + Creates an instance of QWinWidget. \a parentWnd is a pointer to an + MFC window object. If a \a parent is provided the object is owned + by that QObject. \a f is passed on to the QWidget constructor. +*/ +QWinWidget::QWinWidget(CWnd *parentWnd, QObject *parent, Qt::WFlags f) +: QWidget(0, f), hParent(parentWnd ? parentWnd->m_hWnd : 0), prevFocus(0), reenable_parent(false) +{ + if (parent) + QObject::setParent(parent); + + init(); +} +#endif + + +void QWinWidget::init() +{ + Q_ASSERT(hParent); + + if (hParent) { + // make the widget window style be WS_CHILD so SetParent will work + QT_WA({ + SetWindowLong(winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + }, { + SetWindowLongA(winId(), GWL_STYLE, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + }) + SetParent(winId(), hParent); + + QEvent e(QEvent::EmbeddingControl); + QApplication::sendEvent(this, &e); + } +} + +/*! + Destroys this object, freeing all allocated resources. +*/ +QWinWidget::~QWinWidget() +{ +} + +/*! + Returns the handle of the native Win32 parent window. +*/ +HWND QWinWidget::parentWindow() const +{ + return hParent; +} + +/*! + \reimp +*/ +void QWinWidget::childEvent(QChildEvent *e) +{ + QObject *obj = e->child(); + if (obj->isWidgetType()) { + if (e->added()) { + if (obj->isWidgetType()) { + obj->installEventFilter(this); + } + } else if (e->removed() && reenable_parent) { + reenable_parent = false; + EnableWindow(hParent, true); + obj->removeEventFilter(this); + } + } + QWidget::childEvent(e); +} + +/*! \internal */ +void QWinWidget::saveFocus() +{ + if (!prevFocus) + prevFocus = ::GetFocus(); + if (!prevFocus) + prevFocus = parentWindow(); +} + +/*! + Shows this widget. Overrides QWidget::show(). + + \sa showCentered() +*/ +void QWinWidget::show() +{ + saveFocus(); + QWidget::show(); +} + +/*! + Centers this widget over the native parent window. Use this + function to have Qt toplevel windows (i.e. dialogs) positioned + correctly over their native parent windows. + + \code + QWinWidget qwin(hParent); + qwin.center(); + + QMessageBox::information(&qwin, "Caption", "Information Text"); + \endcode + + This will center the message box over the client area of hParent. +*/ +void QWinWidget::center() +{ + const QWidget *child = qFindChild(this); + if (child && !child->isWindow()) { + qWarning("QWinWidget::center: Call this function only for QWinWidgets with toplevel children"); + } + RECT r; + GetWindowRect(hParent, &r); + setGeometry((r.right-r.left)/2+r.left, (r.bottom-r.top)/2+r.top,0,0); +} + +/*! + \obsolete + + Call center() instead. +*/ +void QWinWidget::showCentered() +{ + center(); + show(); +} + +/*! + Sets the focus to the window that had the focus before this widget + was shown, or if there was no previous window, sets the focus to + the parent window. +*/ +void QWinWidget::resetFocus() +{ + if (prevFocus) + ::SetFocus(prevFocus); + else + ::SetFocus(parentWindow()); +} + +/*! \reimp +*/ +bool QWinWidget::winEvent(MSG *msg, long *) +{ + if (msg->message == WM_SETFOCUS) { + Qt::FocusReason reason; + if (::GetKeyState(VK_SHIFT) < 0) + reason = Qt::BacktabFocusReason; + else + reason = Qt::TabFocusReason; + QFocusEvent e(QEvent::FocusIn, reason); + QApplication::sendEvent(this, &e); + } + + return false; +} + +/*! + \reimp +*/ +bool QWinWidget::eventFilter(QObject *o, QEvent *e) +{ + QWidget *w = (QWidget*)o; + + switch (e->type()) { + case QEvent::WindowDeactivate: + if (w->isModal() && w->isHidden()) + BringWindowToTop(hParent); + break; + + case QEvent::Hide: + if (reenable_parent) { + EnableWindow(hParent, true); + reenable_parent = false; + } + resetFocus(); + if (w->testAttribute(Qt::WA_DeleteOnClose) && w->isWindow()) + deleteLater(); + break; + + case QEvent::Show: + if (w->isWindow()) { + saveFocus(); + hide(); + if (w->isModal() && !reenable_parent) { + EnableWindow(hParent, false); + reenable_parent = true; + } + } + break; + + case QEvent::Close: + ::SetActiveWindow(hParent); + if (w->testAttribute(Qt::WA_DeleteOnClose)) + deleteLater(); + break; + + default: + break; + } + + return QWidget::eventFilter(o, e); +} + +/*! \reimp +*/ +void QWinWidget::focusInEvent(QFocusEvent *e) +{ + QWidget *candidate = this; + + switch (e->reason()) { + case Qt::TabFocusReason: + case Qt::BacktabFocusReason: + while (!(candidate->focusPolicy() & Qt::TabFocus)) { + candidate = candidate->nextInFocusChain(); + if (candidate == this) { + candidate = 0; + break; + } + } + if (candidate) { + candidate->setFocus(e->reason()); + if (e->reason() == Qt::BacktabFocusReason || e->reason() == Qt::TabFocusReason) { + candidate->setAttribute(Qt::WA_KeyboardFocusChange); + candidate->window()->setAttribute(Qt::WA_KeyboardFocusChange); + } + if (e->reason() == Qt::BacktabFocusReason) + QWidget::focusNextPrevChild(false); + } + break; + default: + break; + } +} + +/*! \reimp +*/ +bool QWinWidget::focusNextPrevChild(bool next) +{ + QWidget *curFocus = focusWidget(); + if (!next) { + if (!curFocus->isWindow()) { + QWidget *nextFocus = curFocus->nextInFocusChain(); + QWidget *prevFocus = 0; + QWidget *topLevel = 0; + while (nextFocus != curFocus) { + if (nextFocus->focusPolicy() & Qt::TabFocus) { + prevFocus = nextFocus; + topLevel = 0; + } else if (nextFocus->isWindow()) { + topLevel = nextFocus; + } + nextFocus = nextFocus->nextInFocusChain(); + } + + if (!topLevel) { + return QWidget::focusNextPrevChild(false); + } + } + } else { + QWidget *nextFocus = curFocus; + while (1) { + nextFocus = nextFocus->nextInFocusChain(); + if (nextFocus->isWindow()) + break; + if (nextFocus->focusPolicy() & Qt::TabFocus) { + return QWidget::focusNextPrevChild(true); + } + } + } + + ::SetFocus(hParent); + + return true; +} diff --git a/qtwinmigrate/qwinwidget.h b/qtwinmigrate/qwinwidget.h new file mode 100644 index 0000000..59ed7d4 --- /dev/null +++ b/qtwinmigrate/qwinwidget.h @@ -0,0 +1,64 @@ + +// Declaration of the QWinWidget classes + +#ifndef QWINWIDGET_H +#define QWINWIDGET_H + +#include +#include "qmfcapp.h" + +class CWnd; + +#if defined(Q_WS_WIN) +# if !defined(QT_QTWINMIGRATE_EXPORT) && !defined(QT_QTWINMIGRATE_IMPORT) +# define QT_QTWINMIGRATE_EXPORT +# elif defined(QT_QTWINMIGRATE_IMPORT) +# if defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# endif +# define QT_QTWINMIGRATE_EXPORT __declspec(dllimport) +# elif defined(QT_QTWINMIGRATE_EXPORT) +# undef QT_QTWINMIGRATE_EXPORT +# define QT_QTWINMIGRATE_EXPORT __declspec(dllexport) +# endif +#else +# define QT_QTWINMIGRATE_EXPORT +#endif + +class QT_QTWINMIGRATE_EXPORT QWinWidget : public QWidget +{ + Q_OBJECT +public: + QWinWidget( HWND hParentWnd, QObject *parent = 0, Qt::WFlags f = 0 ); +#ifdef QTWINMIGRATE_WITHMFC + QWinWidget( CWnd *parnetWnd, QObject *parent = 0, Qt::WFlags f = 0 ); +#endif + ~QWinWidget(); + + void show(); + void center(); + void showCentered(); + + HWND parentWindow() const; + +protected: + void childEvent( QChildEvent *e ); + bool eventFilter( QObject *o, QEvent *e ); + + bool focusNextPrevChild(bool next); + void focusInEvent(QFocusEvent *e); + + bool winEvent(MSG *msg, long *result); + +private: + void init(); + + void saveFocus(); + void resetFocus(); + + HWND hParent; + HWND prevFocus; + bool reenable_parent; +}; + +#endif // QWINWIDGET_H diff --git a/qwidgethostnative.cpp b/qwidgethostnative.cpp new file mode 100644 index 0000000..a8112a6 --- /dev/null +++ b/qwidgethostnative.cpp @@ -0,0 +1,104 @@ +#include "qwidgethostnative.h" + +#include "qtjambi_core.h" + +#include +#include + +#include + +static const char *qtjambi_awt_title = "Qt Jambi / AWT"; + +QWidgetHostNative::QWidgetHostNative(jobject parentWindow) + +#if defined(Q_OS_WIN32) + : QWIDGETHOSTNATIVE_BASECLASS(getWindowHandle(parentWindow)) +#else + : QWIDGETHOSTNATIVE_BASECLASS(0) +#endif + +{ +#if !defined(Q_OS_WIN32) + embedInto(getWindowHandle(parentWindow)); +#endif +} + +WId QWidgetHostNative::getWindowHandle(jobject awtWidget) +{ + Q_ASSERT(awtWidget != 0); + + // Call winId() to make sure widget gets a window handle + QApplication::setAttribute(Qt::AA_NativeWindows); + + JNIEnv *env = qtjambi_current_environment(); + Q_ASSERT(env != 0); + + JAWT awt; + awt.version = JAWT_VERSION_1_3; + if (JAWT_GetAWT(env, &awt) == JNI_FALSE) { + qWarning("%s [%s:%d]: Couldn't get JAWT interface\n", qtjambi_awt_title, __FILE__, __LINE__); + return false; + } + + WId awtWindowId = 0; + { + JAWT_DrawingSurface *ds; + ds = awt.GetDrawingSurface(env, awtWidget); + if (ds == 0) { + qWarning("%s [%s:%d]: Couldn't get drawing surface\n", qtjambi_awt_title, __FILE__, __LINE__); + return false; + } + + jint lock = ds->Lock(ds); + if (lock & JAWT_LOCK_ERROR) { + qWarning("%s [%s:%d]: Couldn't lock drawing surface\n", qtjambi_awt_title, __FILE__, __LINE__); + return false; + } + + { + JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds); + if (dsi == 0) { + qWarning("%s [%s:%d]: Couldn't get drawing surface info\n", qtjambi_awt_title, __FILE__, __LINE__); + return false; + } + +#if defined(Q_OS_WIN32) + awtWindowId = reinterpret_cast(dsi->platformInfo)->hwnd; +#else + awtWindowId = reinterpret_cast(dsi->platformInfo)->drawable; +#endif + ds->FreeDrawingSurfaceInfo(dsi); + } + + ds->Unlock(ds); + awt.FreeDrawingSurface(ds); + } + + return awtWindowId; +} + +/* ### Empty implementations to work around limitation in generator */ +void QWidgetHostNative::childEvent(QChildEvent *e) +{ + QWIDGETHOSTNATIVE_BASECLASS::childEvent(e); +} + +bool QWidgetHostNative::eventFilter(QObject *o, QEvent *e) +{ + return QWIDGETHOSTNATIVE_BASECLASS::eventFilter(o, e); +} + +void QWidgetHostNative::focusInEvent(QFocusEvent *e) +{ + QWIDGETHOSTNATIVE_BASECLASS::focusInEvent(e); +} + +bool QWidgetHostNative::event(QEvent *e) +{ + return QWIDGETHOSTNATIVE_BASECLASS::event(e); +} + +void QWidgetHostNative::resizeEvent(QResizeEvent *e) +{ + QWIDGETHOSTNATIVE_BASECLASS::resizeEvent(e); +} diff --git a/qwidgethostnative.h b/qwidgethostnative.h new file mode 100644 index 0000000..e753b75 --- /dev/null +++ b/qwidgethostnative.h @@ -0,0 +1,34 @@ +#ifndef QWIDGETHOSTNATIVE_H +#define QWIDGETHOSTNATIVE_H + +#include + +#if defined(QT_JAMBI_RUN) +# define QWIDGETHOSTNATIVE_BASECLASS QWidget +#elif defined(Q_OS_WIN32) +# include "qwinwidget.h" +# define QWIDGETHOSTNATIVE_BASECLASS QWinWidget +#else +# include +# define QWIDGETHOSTNATIVE_BASECLASS QX11EmbedWidget +#endif + +#include + +class QWidgetHostNative: public QWIDGETHOSTNATIVE_BASECLASS +{ +public: + QWidgetHostNative(jobject parentWindow); + +protected: + void childEvent(QChildEvent *e); + bool eventFilter(QObject *o, QEvent *e); + void focusInEvent(QFocusEvent *e); + bool event(QEvent *); + void resizeEvent(QResizeEvent *); + +private: + WId getWindowHandle(jobject window); +}; + +#endif diff --git a/typesystem_qawt.xml b/typesystem_qawt.xml new file mode 100644 index 0000000..b0e252b --- /dev/null +++ b/typesystem_qawt.xml @@ -0,0 +1,14 @@ + + + + + + com.trolltech.qt.Utilities.Configuration oldConfiguration = com.trolltech.qt.Utilities.configuration; + com.trolltech.qt.Utilities.configuration = com.trolltech.qt.Utilities.Configuration.Release; + com.trolltech.qt.Utilities.loadLibrary("jawt"); + com.trolltech.qt.Utilities.configuration = oldConfiguration; + + + + + -- cgit v1.2.3