Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "SWT/Developer Guide"

< SWT
(Introduction)
(Source tree organization)
Line 61: Line 61:
 
This repository is organized around five root folders
 
This repository is organized around five root folders
  
* bundles — where the code actually is
+
* bundles — where the code actually is written. It contains a project with the code of the SWT Tools (org.eclipse.swt.tools), a project org.eclipse.swt.fragments.localbuild (??? Don't know what it is about) and '''org.eclipse.swt''' the main project.
 
* features — contains only one feature: ''SWT Tools''. It is used to be able to install all [https://www.eclipse.org/swt/tools.php SWT Tools] (JNI Generator, Sleak and SWT Spy) in the IDE at once.
 
* features — contains only one feature: ''SWT Tools''. It is used to be able to install all [https://www.eclipse.org/swt/tools.php SWT Tools] (JNI Generator, Sleak and SWT Spy) in the IDE at once.
 
* local-build — ???
 
* local-build — ???
 
* examples — code samples and [https://www.eclipse.org/swt/snippets/ snippets]
 
* examples — code samples and [https://www.eclipse.org/swt/snippets/ snippets]
 
* tests — [http://junit.org/ JUnit] and performance tests.
 
* tests — [http://junit.org/ JUnit] and performance tests.
 +
 +
=== eclipse.platform.swt/bundles/org.eclipse.swt ===
 +
 +
It is a Java (JDT) project. It has a lot of source folders (between 25 and 30 depending on the platform you are building). The source code is split by features: printing support, browser support, OpenGL... Within each source folder, the code is organized by WS (win32, cocoa, gtk...). When some code does not require native call, it is written in pure Java and located in a folder named ''common'' (sometimes ''common_j2se'' or ''common_j2me'' when the WS is supported on mobile device where only [http://en.wikipedia.org/wiki/Java_Platform,_Micro_Edition J2ME] can be run). Let's take an example with the folder ''Eclipse SWT Drag and Drop'' (DnD). It contains 6 subfolders:
 +
 +
* cocoa
 +
* common
 +
* emulated
 +
* gtk
 +
* win32
 +
* wpf
 +
 +
It means that for compiling DnD support on OS X with Cocoa, I need the sources in <code>cocoa</code> and <code>common</code> but for Windows, I need <code>win32</code> and <code>common</code>. For platform without native DnD support both <code>common</code> and <code>emulated</code> are needed. You know see a crucial point of SWT: each platform has the same '''public''' API but classes and implementations are different. For instance, in the Windows implementation of the DnD support, there is a helper class <code>OleEnumFORMATETC</code> which is package private and specific to the DnD support on Windows. There is one Java source class file <code>org.eclipse.swt.dnd.DropTarget.java</code> in each subfolder of the DnD source folder. Each one '''must''' expose the same API as the others and '''must''' have the same Javadoc as client of these classes will only one version running on their system later. The issue with the exposed API is even harder to maintain for developers because with SWT you code against classes and not interfaces. There is no inversion of control (with factory or dependency injection framework). You call <code>new Button(Composite, int).getText()</code> wether you are on Windows, OS X or Linux and Button#getText() is not enforced in all implementation by the fact that Button implement an interface.
  
 
=== eclipse.platform.swt.binaries ===
 
=== eclipse.platform.swt.binaries ===
  
This repository contains only one folder: ''bundles'' which contains one folder/project per support combination of OS/WS/ARCH
+
This repository contains only one folder: ''bundles'' which contains one folder/project per supported combination of OS/WS/ARCH
  
 
== JNI Generator ==
 
== JNI Generator ==
  
 
SWT uses a home made tool call JNI Generator to generate both <code>.c</code> and <code>.h</code> files. The source of this tool are located in the project [http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/bundles/org.eclipse.swt.tools/JNI%20Generation org.eclipse.swt.tools (JNI Generation subfolder)]. A introductory documentation of this tool is [https://www.eclipse.org/swt/jnigen.php available online]. Basically, it parses the file OS.java in the current classpath and generates os.c and os.h accordingly. Whenever you change something in OS.java in your IDE, a dedicated builder (org.eclipse.swt.tools.jnibuilder) is called along with the Java compilation to update os.c and os.h.
 
SWT uses a home made tool call JNI Generator to generate both <code>.c</code> and <code>.h</code> files. The source of this tool are located in the project [http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/bundles/org.eclipse.swt.tools/JNI%20Generation org.eclipse.swt.tools (JNI Generation subfolder)]. A introductory documentation of this tool is [https://www.eclipse.org/swt/jnigen.php available online]. Basically, it parses the file OS.java in the current classpath and generates os.c and os.h accordingly. Whenever you change something in OS.java in your IDE, a dedicated builder (org.eclipse.swt.tools.jnibuilder) is called along with the Java compilation to update os.c and os.h.

Revision as of 13:28, 16 March 2015

Introduction

SWT use native operating systems widget toolkits.

The most common supported operating system (aka OS) supported by SWT are:

  • Windows
  • Linux
  • OS X

The most common native toolkits (aka windowing system or WS) for common supported platforms are:

  • Win32 on Windows
  • GTK on Linux
  • Cocoa on OS X

Finally, SWT run on several CPU architectures (aka ARCH), the two most common being:

  • x86 (also known as i386, IA-32 or i586)
  • x86_64 (also known as amd64 or x64)

SWT is a Java framework. In order to be able to use the native toolkits, SWT has to use a feature of Java to call native code. This feature is called Java Native Interface (JNI). JNI lets you define methods in Java with the keyword native and the behavior of this method will be delegated to some native code (C/C++ or Objective C most of the time).

Usually with JNI, you would have to write the native code manually, and run the javah command on the Java files with native method to generate header that would bind your Java code and the native code (before compiling it). You would end up with something like that:

  • HelloWorld.java with a method declared as "native". This class is compiled with javac to a .class file.
  • HelloWorld.h is a C header file with the signature of the native method. It can be generated by the program javah (available with the Java SDK).
  • libHelloWorld.c, the native C code using system calls and JNI data structures to manipulate Java objects. This file requires to #include HelloWorld.h.

This method has several drawbacks. First, writing native code is very error prone. It is especially the case with SWT because the team chose to have a very thin layer between Java and the native toolkit. Basically they chose to create a native Java method for one native system call. Lets take the gdk_window_set_cursor GTK system call. In the file OS.java, SWT developers has to write

public static final native void gdk_window_set_cursor(long window, long cursor);


and in the file os.c

JNIEXPORT void JNICALL gdk_window_set_cursor
	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
{
	OS_NATIVE_ENTER(env, that, _1gdk_1window_1set_1cursor_FUNC);
	gdk_window_set_cursor((GdkWindow *)arg0, (GdkCursor *)arg1);
	OS_NATIVE_EXIT(env, that, _1gdk_1window_1set_1cursor_FUNC);
}


This is pretty straightforward and cumbersome to write manually.

A second drawback about using javah is that it does not handle 32/64 bits automatically. You have to duplicate your code if you want to handle both of them. The main difference when interacting with a 64 bits OS instead of a 32 bits one, is that pointer are 64 bits long instead of 32 bits. From a programmer point of view, Java is agnostic to the CPU's word size... except when doing native calls. So every integers representing a pointer in a system call has to mapped to Java long integer when using a 64 bits OS and mapped to a simple int when runnning on a 32 bits OS. In the previous example gdk_window_set_cursor, window and cursor are both pointers. This native method will work well with the 64 bits version of GTK, but not with the 32 bits as windows and cursor are declared as long integers. The overhead of writing both versions is heavyweight so SWT's team tackles the two drawbacks at once. Read more about it later.

Source tree organization

SWT is developed in two Git repositories:

eclipse.platform.swt

This repository is organized around five root folders

  • bundles — where the code actually is written. It contains a project with the code of the SWT Tools (org.eclipse.swt.tools), a project org.eclipse.swt.fragments.localbuild (??? Don't know what it is about) and org.eclipse.swt the main project.
  • features — contains only one feature: SWT Tools. It is used to be able to install all SWT Tools (JNI Generator, Sleak and SWT Spy) in the IDE at once.
  • local-build — ???
  • examples — code samples and snippets
  • tests — JUnit and performance tests.

eclipse.platform.swt/bundles/org.eclipse.swt

It is a Java (JDT) project. It has a lot of source folders (between 25 and 30 depending on the platform you are building). The source code is split by features: printing support, browser support, OpenGL... Within each source folder, the code is organized by WS (win32, cocoa, gtk...). When some code does not require native call, it is written in pure Java and located in a folder named common (sometimes common_j2se or common_j2me when the WS is supported on mobile device where only J2ME can be run). Let's take an example with the folder Eclipse SWT Drag and Drop (DnD). It contains 6 subfolders:

  • cocoa
  • common
  • emulated
  • gtk
  • win32
  • wpf

It means that for compiling DnD support on OS X with Cocoa, I need the sources in cocoa and common but for Windows, I need win32 and common. For platform without native DnD support both common and emulated are needed. You know see a crucial point of SWT: each platform has the same public API but classes and implementations are different. For instance, in the Windows implementation of the DnD support, there is a helper class OleEnumFORMATETC which is package private and specific to the DnD support on Windows. There is one Java source class file org.eclipse.swt.dnd.DropTarget.java in each subfolder of the DnD source folder. Each one must expose the same API as the others and must have the same Javadoc as client of these classes will only one version running on their system later. The issue with the exposed API is even harder to maintain for developers because with SWT you code against classes and not interfaces. There is no inversion of control (with factory or dependency injection framework). You call new Button(Composite, int).getText() wether you are on Windows, OS X or Linux and Button#getText() is not enforced in all implementation by the fact that Button implement an interface.

eclipse.platform.swt.binaries

This repository contains only one folder: bundles which contains one folder/project per supported combination of OS/WS/ARCH

JNI Generator

SWT uses a home made tool call JNI Generator to generate both .c and .h files. The source of this tool are located in the project org.eclipse.swt.tools (JNI Generation subfolder). A introductory documentation of this tool is available online. Basically, it parses the file OS.java in the current classpath and generates os.c and os.h accordingly. Whenever you change something in OS.java in your IDE, a dedicated builder (org.eclipse.swt.tools.jnibuilder) is called along with the Java compilation to update os.c and os.h.

Back to the top