Java Window Integration
This section discusses experiences obtained during the development of Java-OpenOffice.org integration. Usually, developers use the OfficeBean for this purpose. The following provides background information about possible strategies to reach this goal.
There are multiple possibilities to integrate local windows with OpenOffice.org windows. This chapter shows the integration of OpenOffice.org windows into a Java bean environment. Some of this information may be helpful with other local window integrations.
The Window Handle
An important precondition is the existence of a system window handle of the own Java window. For this, use a
java.awt.Canvas and the following JNI methods:
- a method to query the window handle (HWND on Windows, X11 ID on UNIX)
- a method to identify the operating system, for example, UNIX, Windows, or Macintosh
For an example, see bean/com/sun/star/beans/LocalOfficeWindow.java
The two methods
getNativeWindowSystemType() are declared and exported, but implemented for windows in bean/native/win32/com_sun_star_beans_LocalOfficeWindow.c through JNI
|It has to be a java.awt.Canvas. These JNI methods cannot be implemented at a Swing control, because it does not have its own system window. You can use a java.awt.Canvas in a Swing container environment.|
|The handle is not available before the window is visible, otherwise the JNI function does not work. One possibility is to cache the handle and set it in show() or setVisible().|
Using the Window Handle
The window handle create the OpenOffice.org window. There are two ways to accomplish this:
This option is mentioned because there are situations where this is the only feasible method. The knowledge of this option can help in other situations.
Add the UNO interface com.sun.star.awt.XWindowPeer so that it is usable for the OpenOffice.org window toolkit. This interface can have an empty implementation. In com.sun.star.awt.XToolkit:createWindow(), another interface com.sun.star.awt.XSystemDependentWindowPeer is expected that queries the HWND. Thus,
XWindowPeer is for transporting and com.sun.star.awt.XSystemDependentWindowPeer queries the HWND.
com.sun.star.awt.XToolkit xToolkit = (com.sun.star.awt.XToolkit)UnoRuntime.queryInterface( com.sun.star.awt.XToolkit.class, xSMGR.createInstance("com.sun.star.awt.Toolkit")); // this is the canvas object with the JNI methods aParentView = ... // some JNI methods cannot work before this aParentView.setVisible(true); // now wrap the canvas (JavaWindowPeerFake) and add the necessary interfaces com.sun.star.awt.XWindowPeer xParentPeer = (com.sun.star.awt.XWindowPeer)UnoRuntime.queryInterface( com.sun.star.awt.XWindowPeer.class, new JavaWindowPeerFake(aParentView)); com.sun.star.awt.WindowDescriptor aDescriptor = new com.sun.star.awt.WindowDescriptor(); aDescriptor.Type = com.sun.star.awt.WindowClass.TOP; aDescriptor.WindowServiceName = "workwindow"; aDescriptor.ParentIndex = 1; aDescriptor.Parent = xParentPeer; aDescriptor.Bounds = new com.sun.star.awt.Rectangle(0,0,0,0); if (aParentView.getNativeWindowSystemType()==com.sun.star.lang.SystemDependent.SYSTEM_WIN32) aDescriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.SHOW; else aDescriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.SYSTEMDEPENDENT; // now the toolkit can create an com.sun.star.awt.XWindow com.sun.star.awt.XWindowPeer xPeer = xToolkit.createWindow( aDescriptor ); com.sun.star.awt.XWindow xWindow = (com.sun.star.awt.XWindow)UnoRuntime.queryInterface( com.sun.star.awt.XWindow.class, xPeer);
The com.sun.star.awt.Toolkit service implements the interface com.sun.star.awt.XSystemChildFactory with a method
createSystemChild(). This accepts an any with a wrapped HWND or X Window ID, as long and the system type, such as Windows, Java, and UNIX directly. Here you create an com.sun.star.awt.XWindow. This method cannot be used in OpenOffice.org build versions before src642, because the process ID parameter is unknown to the Java environment. Newer versions do not check this parameter, thus this new, method works.
|As a user of com.sun.star.awt.XSystemChildFactory:createSystemChild() ensure that your client (Java application) and your server (OpenOffice.org) use the same display. Otherwise the window handle is not interchangeable.|
com.sun.star.awt.XToolkit xToolkit = (com.sun.star.awt.XToolkit)UnoRuntime.queryInterface( com.sun.star.awt.XToolkit.class, xSMGR.createInstance("com.sun.star.awt.Toolkit")); // this is the canvas with the JNI functions aParentView = ... // some JNI funtions will not work without this aParentView.setVisible(true); // no wrapping necessary, simply use the HWND com.sun.star.awt.XSystemChildFactory xFac = (com.sun.star.awt.XSystemChildFactory)UnoRuntime.queryInterface( com.sun.star.awt.XSystemChildFactory.class, xToolkit); Integer nHandle = aParentView.getHWND(); byte lIgnoredProcessID = new byte; com.sun.star.awt.XWindowPeer xPeer = xFac.createSystemChild( (Object)nHandle, lIgnoredProcessID, com.sun.star.lang.SystemDependent.SYSTEM_WIN32); com.sun.star.awt.XWindow xWindow = (com.sun.star.awt.XWindow)UnoRuntime.queryInterface( com.sun.star.awt.XWindow.class, xPeer);
|The old method still works and can be used, but it should be considered deprecated. If in doubt, implement both and try the new method at runtime. If it does not work, try the hack.|
Another difficulty is resizing the window. Normally, the child window expects resize events of the parent. The child does not resize it window, because it must know the layout of the parent window. The VCL, OpenOffice.org's windowing engine creates a special system child window, thus we can resize windows.
The parent window can be filled "full size" with the child window, but only for UNIX and not for Windows. The VCL's implementation is system dependent.
The bean deals with this issue by adding another function to the local library. Windows adds arbitrary properties to an HWND. You can also subclass the window, that is, each Windows window has a function pointer or callback to the function that performs the event handling (WindowProcedure). Using this, it is possible to treat events by calling your own methods. This is useful whenever the window is not created by you and you need to influence the behavior of the window.
In this case, the Java window has not been created by us, but we need to learn about resize events to forward these to the OpenOffice.org window. Look at the file bean/native/win32/com_sun_star_beans_LocalOfficeWindow.c, and find the method
OpenOfficeWndProc(). In the first call of the JNI function
Java_com_sun_star_beans_LocalOfficeWindow_getNativeWindow() of this file, the own handler is applied to the foreign window.
In the future, VCL will do this sub-classing by itself, even on Windows. This will lead to equal behavior between Windows and UNIX.
The initial size of the window is a related problem. If a canvas is connected with a OpenOffice.org window, set both sizes to a valid, positive value, otherwise the OpenOffice.org window will not be visible. If you are using a non-product build of OpenOffice.org, you see an assertion failed "small world isn't it". This might change when the sub-classing is done by VCL in the future.
There is still one unresolved problem. The code mentioned above works with Java 1.3, but not for Java 1.4. There, the behavior of windows is changed. Where Java 1.3 sends real resize events from the own
WindowProc, Java 1.4 does a re-parenting. The canvas window is destroyed and created again. This leads to an empty window with no OpenOffice.org window. This problem is under investigation.
More Remote Problems
There are additional difficulties to window handles and local window handles. Some personal experiences of one of the OpenOffice.org authors are provided:
- Listeners in Java should be implemented in a thread. The problem is that SolarMutex, a mutex semaphore of OpenOffice.org, one-way UNO methods and the global Java GUI thread do not work together.
- The Java applet should release its listeners. If they stay in the containers of OpenOffice.org after the Java process ends, UNO throws a com.sun.star.lang.DisposedException, which are not caught correctly. Java does not know destructors, therefore it is a difficult to follow this advice. One possibility is to register a Thread object at
ShutDownHook. This is called even when CTRL-C is pressed on the command line where you can deregister the listeners. Because listeners are threads, there is some effort.
|Content on this page is licensed under the Public Documentation License (PDL).|