SWT: The Standard Widget Toolkit
PART 1: Implementation Strategy for Java™ Natives
The first in a series of articles about the design ideas behind SWT.
Summary
SWT is the software component that delivers native widget functionality for the Eclipse platform in an operating system independent manner. It is analogous to AWT/Swing in Java with a difference - SWT uses a rich set of native widgets. Even in an ideal situation, industrial strength cross platform widget libraries are very difficult to write and maintain. This is due to the inherent complexity of widget systems and the many subtle differences between platforms. There are several basic approaches that have helped significantly to reduce the complexity of the problem and deliver high quality libraries. This article discusses one of them, the low level implementation techniques used to implement SWT on different platforms. Examples are drawn from the Windows® and Motif implementations.
By Steve Northover, OTI
March 22, 2001
Portable and Native - It Can't Be Done!
Developers demand portable graphics and widgets to allow them to build user interfaces that are competitive with shrink-wrapped applications built using platform specific tools. They need access to platform specific features, with well defined API boundaries. SWT delivers this functionality using a small and consistent API. This API is implemented on different platforms using a combination of Java code and JNI natives specific to each platform.
SWT is implemented entirely in one language: Java. How can this be true when SWT uses native widgets that provide an API in C? The answer is that Java provides a native interface to C (JNI) that is used by SWT to invoke the operating system from Java code. JNI is the standard mechanism used by all Java programs to invoke code written in C. SWT goes one step further by enforcing a one-to-one mapping between Java native methods and operating system calls. The fact that this mapping is strictly enforced is one of the most critical factors in the success of SWT.
A Tale of Two Implementations
Let's take a look at the implementation of SWT
Text widget on two different platforms. The
Text widget provides the ability to set the selection. SWT application code that uses this API might look something like this:
/* Select positions 2 to 5 */
text.setText ("0123456780");
text.setSelection (2, 5);
The method signature for setSelection in class Text looks like this:
/**
* Sets the selection.
* <p>
* Indexing is zero based. The range of a selection is from 0..N
* where N is the number of characters in the widget.
*/
public void setSelection (int start, int end)
Here is the Windows implementation of setSelection:
public void setSelection (int start, int end) {
OS.SendMessage (handle, OS.EM_SETSEL, start, end);
}
What are SendMessage and EM_SETSEL? Windows programmers recognize this right away. It's SendMessage, the mechanism that is used to talk to Windows controls. EM_SETSEL is the message that tells the text control to set the selection. It's not easy reading, but it is familiar to a Windows programmer. The rest of us get to read the Microsoft® Developer Network (MSDN) Library!
Here is the Java code for the SWT class OS on Windows:
class OS {
public static final int EM_SETSEL = 0xB1;
public static final native int SendMessage (int hWnd, int Msg, int wParam, int lParam);
...
}
How is the SendMessage native implemented? Here is the C code on Windows:
JNIEXPORT jint JNICALL Java_org_eclipse_swt_internal_win32_OS_SendMessage__IIII
(JNIEnv *env, jclass that, jint hWnd, jint Msg, jint wParam, jint lParam)
{
return (jint) SendMessage((HWND)hWnd, Msg, wParam, lParam);
}
Notice that the only thing this native does is pass the Java call straight on through to the Windows API. But what about other operating systems? Does the fact that setSelection is implemented in terms of the Windows API mean that SWT is not portable? While it is true that the Windows implementation of Text is not portable, application code that uses Text is. How is this achieved? SWT provides a different Text class for each platform, but the signature of every public method is the same. Java code that calls SWT does not know or care which Text class is referenced at run time. SendMessage is not SWT API.
Here is the implementation of setSelection on Motif (Java and JNI C):
public void setSelection (int start, int end) {
int xDisplay = OS.XtDisplay (handle);
if (xDisplay == 0) return;
OS.XmTextSetSelection (handle, start, end, OS.XtLastTimestampProcessed (xDisplay));
OS.XmTextSetInsertionPosition (handle, end);
}
class OS {
public static final native void XmTextSetSelection (int widget, int first, int last, int time);
public static final native int XtLastTimestampProcessed (int display);
public static final native void XmTextSetInsertionPosition (int widget, int position);
public static final native int XtDisplay (int widget);
...
}
JNIEXPORT void JNICALL Java_org_eclipse_swt_internal_motif_OS_XmTextSetSelection
(JNIEnv *env, jclass that, jint widget, jint first, jint last, jint time)
{
XmTextSetSelection((Widget)widget, first, last, time);
}
...
What are XtDisplay, XmTextSetSelection, XtLastTimestampProcessed and XmTextSetInsertionPosition? They don't mean much to a Windows programmer, but they are familiar to anyone who has ever programmed Motif. Now it's the Windows programmer's turn to consult the Motif man pages!
The example code above was taken directly from SWT but has been simplified by removing range and error checking code for the sake of the example. However, the code that is doing the real work - setting the selection - is identical to that found in the product.
One to One Mapping - No Custom Natives
Take a moment to review the Java and C code for
setSelection in the previous section. Wouldn't it be easier to implement one
Text class for all SWT platforms and hide the platform differences in the natives? Such an implementation might look like this:
public void setSelection (int start, int end) {
nativeSetSelection (start, end)
}
static final native void nativeSetSelection (int start, int end);
JNIEXPORT void JNICALL Java_org_eclipse_swt_widgets_text_nativeSetSelection
(JNIEnv *env, jclass that, jobject widget, jint first, jint last)
{
#ifdef WINDOWS
HWND hWnd = SWTGetHandleFromJavaWidget (widget);
SendMessage(hWnd, Msg, wParam, lParam);
#endif
#ifdef MOTIF
Widget *w = SWTGetHandleFromJavaWidget (widget);
Display xDisplay = XtDisplay (w);
if (xDisplay == NULL) return;
XmTextSetSelection (w, start, end, XtLastTimestampProcessed (xDisplay));
XmTextSetInsertionPosition (w, end);
#endif
}
Isn't this easier than having a different Text class on each platform? The answer is a resounding "No". Why? In the case of the Text widget, the code to set the selection is pretty simple but even this causes problems. Before we get into the discussion, consider this:
- The non-public native interface must be identical on all platforms. This means there needs to be an implementation of nativeSetSelection everywhere. We also still need to provide the public SWT API. So we need to implement setSelection everywhere. Why would we want to write two portable APIs instead of just one? One API is hard enough to specify and maintain!
- Java is a powerful high level language with features that promote robust code and program stability. It contains reusable class libraries for high level data types such as hash tables and vectors as well as efficient primitive types. Why use C?
Calling the operating system directly from Java helps with debugging. The following problem occurred in an early version of SWT for Windows: when the selection was set in the text widget, sometimes the widget did not scroll to show the i-beam. Where was the problem? The code that demonstrated the problem was complicated, but it was clear from stepping through the Java code and consulting the MSDN Library that the Java implementation of
setSelection was correct. In fact, because of the
one-to-one mapping between our Java natives and C, it was possible to write a simple C example to help isolate the problem and submit a bug report to Microsoft. Why was this so easy? Because, as we have said before, nothing extra ever happens in an SWT native. The Java call is passed right on through to the operating system. This means that C code is guaranteed to exhibit the same behavior. This is great news for debugging and maintenance.
Performance problems are legendary in widget toolkits and finding them is a black art. Where is the performance problem? Is it in the Java code or the natives? Fortunately, SWT natives can't be the problem. We are guaranteed that once we are in a native, the limiting factor is the speed of the operating system - something beyond our control. This is great news for performance tuning: look at the Java code. In fact, one quickly develops a sense of which operating system operations are expensive and which are cheap. Best of all, this knowledge is accurate. A C program that makes the same sequence of operating system calls will exhibit the same performance characteristics. This is a feature of the one-to-one mapping.
What happens when you try to debug a segment fault (or GP)? It's easy enough to step into a Java method and examine arguments but not possible to step into a native. Fortunately, nothing special happens in SWT natives so it's easy enough to isolate the code that is causing the problem. While on the subject of GPs, wouldn't it make sense for SWT natives to check their parameters before making the operating system call? It's tempting to check for NULL or -1 to avoid the crash. On the surface, this seems to make sense - after all, who wants to GP? The answer, of course, is that this would violate the one-to-one mapping and would mean that an equivalent C program would not crash in the same place. That's bad news for debugging and isolating a problem.
For someone implementing and maintaining SWT, the one-to-one mapping is extremely valuable. For example, a Windows programmer knows right away how setSelection works, just by looking at the Java code. Everyone else needs to read the MSDN Library. It's not light reading, but the information is there. The same thing is true for a Motif programmer for SWT on Motif, and for the other supported operating systems. In fact, it's clear exactly how existing features work and new features are to be implemented. The critial point here is that the documentation for the operating system applies to all SWT natives because they are a one-to-one mapping.
Adding new native features to SWT is a straightforward and well defined process. For example, implementing drag and drop and integrating it with the widgets was not difficult, despite the fact that these are two independent services. Why was this so easy? Nothing is hidden in the C code. All of the operating system resources needed to implement SWT are manifested as simple Java objects making it easy to understand how SWT works and to make changes. This allows SWT to be customized to support new platform dependent widgets and operating system services as they become available.
One last point: JNI is rich and powerful. It allows you to allocate Java objects in C, get and set Java fields, invoke new VMs and throw exceptions. The operating system, on the other hand, is typically more primitive. For example, most operating system calls that access memory require you to allocate the buffer and pass in the size. Java arrays know their size, so why do we need to pass it in? JNI allows us to allocate objects in C, so why not allocate buffers in the C code? Wouldn't it be better to try and "fix" the operating system API to make it more Java friendly? The answer again is "No". Any deviation from the one-to-one rule means that our Java code no longer behaves the same as the equivalent C code. For example, allocating objects in JNI could introduce a hidden performance problem for Java code inside a tight loop. Also, it may make sense to allocate one large buffer and pass in a smaller size, or reuse a buffer. It's tempting to use JNI features to attempt to "fix" the operating system API but this is a huge mistake.
Conclusion
All of the natives in SWT are implemented using this simple and consistent strategy. There is no C code to hide the low level details of the operating system such as the event loop, callbacks or the thread model. No code reaches back into Java from C to get a field or invoke a method. Nothing is magic - everything is coded in Java using the terminology and documentation of the operating system. Why is this such a big deal? Some might claim that all SWTdoes is use JNI to invoke the operating system - nothing fancy. But that's the whole point. Without a simple set of rules and a sense of restraint - a characteristic of SWT - it's just too easy for a widget toolkit to collapse under its own weight.
分享到:
相关推荐
The Standard Widget Toolkit (SWT) is a new class library for creating graphical user interfaces (GUIs) in Java. Created as part of the Eclipse project, SWT allows developers to build efficient, ...
SWT Widget Fundamentals, Keyboard, Mouse, Control Fundamentals, Display, Tool Bars and Menus, Advanced Controls
The Standard Widget Toolkit (SWT) is a new class library for creating graphical user interfaces (GUIs) in Java. Created as part of the Eclipse project, SWT allows developers to build efficient, ...
### SWT:标准部件工具包(The Standard Widget Toolkit)概览 #### 一、SWT简介与背景 SWT,即标准部件工具包(The Standard Widget Toolkit),是为Java开发者设计的一个强大的图形用户界面(GUI)构建库。它由...
Standard Widget Toolkit(SWT)是Java编程环境中用于创建图形用户界面(GUI)的一种开源库。它与Java的抽象窗口工具包(AWT)和Java Swing不同,SWT直接与操作系统API交互,提供了更加原生、性能更优的用户体验。在...
SWT(Standard Widget Toolkit)是一种用于构建Java图形用户界面的跨平台工具包,它利用本地操作系统资源来创建高性能的应用程序界面。与AWT和Swing等其他Java GUI库不同,SWT更注重于提供原生外观和性能,因此在...
1、percona-toolkit-3.3.1-1-最新版.zip 2、支持centos、redhat、orace linux、ubuntu、debian、麒麟V10、欧拉系统等个版本Linux系统。 3、内部各版本安装包列表如下: percona-toolkit-3.3.1-1.el7.x86_64.rpm、 ...
SWT (Standard Widget Toolkit) 是一个开放源代码的Java库,用于创建图形用户界面(GUI)。这个库由Eclipse基金会维护,它允许Java开发者利用操作系统原生的窗口、控件和外观,使得Java应用程序可以拥有与本地应用...
rknn_toolkit-1.7.1-cp35-cp35m-linux_x86_64.whl
SWT(Standard Widget Toolkit)是Eclipse项目中的一个开源GUI工具包,用于构建Java应用程序的图形用户界面。它提供了一种与操作系统原生GUI控件交互的方式,使得Java应用程序能够拥有与本地应用程序相似的外观和...
percona-toolkit-3.0.12-1.el6.x86_64.rpm
rknn_toolkit-1.6.0-cp36-cp36m-win_amd64.whl
SWT(Standard Widget Toolkit)是由Eclipse项目提供的另一个用于创建GUI的工具包。与Swing不同的是,SWT是基于本地操作系统的窗口系统进行渲染的,这意味着它能够提供更加原生的外观和性能。SWT组件通过本地操作...
文件后缀:.conda 适合系统:windows x64 使用注意:必须安装anaconda3环境且anaconda3为x64版本 安装方式:输入下面命令即可自动安装cuda对应虚拟环境 ...conda install cudatoolkit-11.8.0-hd77b12b_0.conda
"rknn-toolkit-v1.7.3-packages" 是Rockchip公司推出的RKNN(Rockchip Neural Network)工具包的一个版本,主要用于AI模型的部署和优化。RKNN是针对嵌入式设备,特别是Rockchip处理器设计的深度学习推理框架,旨在...
percona-toolkit-2.1.7-1.noarch.rpm,percona工具包。
SWTDesigner是一款强大的图形用户界面(GUI)设计工具,专为Eclipse集成开发环境(IDE)设计,使得开发者能够方便地创建美观且功能丰富的SWT(Standard Widget Toolkit)和JFace应用程序。标题"SWTDesigner_Eclipse...
SWT (Standard Widget Toolkit) 是一个开放源代码的Java库,用于在Java应用程序中创建原生用户界面。这个"swt-4.2.2-win32-win32-x86_64"是一个专为Windows 64位操作系统设计的SWT版本,它包含了必要的组件和库,...
cudatoolkit-10.2.89-h74a9793_1.conda cudatoolkit-10.2.89-h74a9793_1.conda
标题 "swt-4.19M1-cocoa-macosx-x86_64.zip" 暗示这是一个 SWT (Standard Widget Toolkit) 的版本,适用于 macOS 平台的 Cocoa 框架,并且是针对 x86_64 架构的。SWT 是一个开源的 Java 库,它允许 Java 开发人员...