Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[platform-swt-dev] Java-Gnome as a potential PI for SwT - some observations


Hi all interested in the development of SWT on GTK:

I have done some very initial prototyping of what the shape of
SWT on Java-Gnome would look like, so one could write a minimal
SWT example, and so we can make observations on how this shape
is different from the traditional picture of SWT using its own
dedicated PI.

The following oservations open many questions without providing
the answers; so this message is an invitation for discussion
by everyone on the platform-swt-devel list.

The purpose of a PI fr SWT is to provide SWT with means to invoke
GTK functions, and sometimes mess with GTK internal data in cases
where a required SWT functionality can't be achieved through the
API.  Let's look at the simplest possible example of invoking
the GTK API - displaying a GtkWindow ("shell" in SWT terminology).

A C programmer would code something like this:

#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
    GtkWidget *window;
    gtk_init (&argc, &argv);
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_widget_show  (window);
    gtk_main ();
    return(0);
} /* end of HelloWorld.c */


We have omitted
For the ad-hoc SWT_PI, this would translate into:

import org.eclipse.swt.internal.gtk.*;
public class HelloWorld1 {
    public static void main(String[] args) {
        OS.gtk_init_check(new int[] {0}, null);
        int shell = OS.gtk_window_new(OS.GTK_WINDOW_TOPLEVEL);
        OS.gtk_window_set_title(shell, toBytes("TEST"));
        OS.gtk_widget_show(shell);
        OS.gtk_main();
    }
    public byte[] toBytes(String s) {
        byte[] answer = org.eclipse.swt.internal.Converter.wcsToMbcs (null, s, true);
        return answer;
    }
} /* End of HelloWorld1.java */

Using Java-Gnome:

import gnu.gtk.*;
public class HelloWorld2 {
    public static void main(String[] args) {
            Gtk.initCheck(args.length, args);
                GtkWindow window = new GtkWindow(GtkWindowType.TOPLEVEL);
                window.showAll();
                Gtk.main();
    }
} /* End of HelloWorld2.java */


Even at this level, we immediately see several major differences
that are important to SWT.  To list a few:

(1) Java-Gnome provides a hierarchy of classes around the different
    GTK objects and concepts.  SWT_PI provides one flat class, OS,
    with all platform functions.
(2) In SWT_PI, the functions look exactly the platform way, and take
    the same arguments as the C functions.  The "receiver" (e.g.,
    the GtkCList* in gtk_clist_append()) is passed explicitly.
    Also, all the methods are just 1-to-1 JNI stubs, taking
    the same kind of arguments as the native functions.
    In Java-Gnome, the pointers representing the object being acted
    on, are embedded in the receiver of the method; and methods
    do more than just pass straight to the platform function (e.g.,
    converting strings to byte arrays).
(3) In SWT_PI, the "receiver" pointers are represened by the actual
    numeric values of the pointer to OS memory.
    In Java-Gnome, such pointers are hidden in the Java object.

Having this in mind, let's hack together a Display and a Shell,
so we could run this simple SWT example:

/* SWTHelloWorld1.java */
import org.eclipse.swt.widgets.*;
public class SWTHelloWorld1 {
        public static void main(String[] args) {
                Display display = new Display();
                Shell shell = new Shell(display);
                shell.open();
                while (!shell.isDisposed())
                        if (!display.readAndDispatch()) display.sleep();
                display.dispose();
        }
} /* end of SWTHelloWorld1.java */

For simplicity, let's temporarily forget about threading (sync/asyncExec,
checkWidget, synchronizer, etc.), stock colors, subclass checking,
and all possible operations on displays and shells that we will not
need right now.  Most importantly, we'll omit callbacks and also
eveything about disposing (because without callbacks this stuff is
never going to be called).  So, here is Display and Shell:

/* Display.java */
package org.eclipse.swt.widgets;
/*
 * (c) Copyright IBM Corp. 2000, 2002.
 * All Rights Reserved
 */
import org.eclipse.swt.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.graphics.*;
import gnu.gtk.*;

public class Display extends Device {
/* Multiple Displays. */
static Display Default;
static Display [] Displays = new Display [4];
public Display () {
        this (null);
}
public Display (DeviceData data) {
        super (data);
}
protected void create (DeviceData data) {
        createDisplay (data);
        register ();
        if (Default == null) Default = this;
}
synchronized void createDisplay (DeviceData data) {
        Gtk.initCheck(0, new String[] {});
}
void error (int code) {
        throw new SWTError (code);
}
public static synchronized Display getDefault () {
        if (Default == null) Default = new Display ();
        return Default;
}
protected void init () {
        super.init ();
        initializeCallbacks ();
}

void initializeCallbacks () {
}
public boolean readAndDispatch () {
        int status = Gtk.eventsPending ();
        if (status != 0) {
                Gtk.mainIteration ();
                return true;
        }
        return false;
}
synchronized void register () {
        for (int i=0; i<Displays.length; i++) {
                if (Displays [i] == null) {
                        Displays [i] = this;
                        return;
                }
        }
        Display [] newDisplays = new Display [Displays.length + 4];
        System.arraycopy (Displays, 0, newDisplays, 0, Displays.length);
        newDisplays [Displays.length] = this;
        Displays = newDisplays;
}
protected void release () {
        while (readAndDispatch ()) {};
}
void releaseDisplay () {
}
public boolean sleep () {
        try { Thread.sleep(50); } catch (Exception e) {};
        return true;
}
/**
 * Needed by the protocol
 */
public void internal_dispose_GC(int p1, GCData p2) {}
public int internal_new_GC(GCData p1) {return 0;}
} /* End of Display.java */


/* Shell.java */
package org.eclipse.swt.widgets;
/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved
 */

import org.eclipse.swt.*;
import gnu.gtk.*;

public class Shell extends Decorations {
       
        Display display;
        GtkWindow shellHandle;

public Shell () { this ((Display) null); }
public Shell (int style) { this ((Display) null, style); }
public Shell (Display display) {
        this (display, SWT.SHELL_TRIM);
}
public Shell (Display display, int style) {
        this (display, null, style);
}
Shell (Display display, Shell parent, int style) {
        super ();
        createWidget (0);
}
public Shell (Shell parent) {
        this (parent, SWT.TITLE | SWT.CLOSE | SWT.BORDER);
}
public Shell (Shell parent, int style) {
        this (null, parent, style);
}
void createHandle (int index) {
        shellHandle = new GtkWindow(GtkWindowType.TOPLEVEL);
}
void configure () {
}
void showHandle() {
        shellHandle.realize();  // not show!!!
}
void register () {
        // handles are typed => not clear how
}
void hookEvents() {}
void setHandleStyle() {}
void setInitialSize() {}
void createWidget (int index) {
        createHandle    (index);
        hookEvents      ();
        configure       ();
        setHandleStyle  ();
        register        ();
        showHandle      ();
        setInitialSize  ();
}
public void open () {
        setVisible (true);
}
public void setVisible (boolean visible) {
        if (visible) {
                shellHandle.showNow();
        } else {        
                shellHandle.hide();
        }
}
/* No signals yet, and no way to dispose of a shell */
public boolean isDisposed() { return false; }
} /* End of Shell.java */


We see that the differences in the shape of the PI have several consequences.
(1) Because the handles are typed, we can't reuse them.  E.g.,
    we can't use topHandle from the superclass.
(2) Java-Gnome eliminates the problem where we stuff a pointer into
    a Java int - what if pointers are not 32 bits? (e.g. alpha?)
(3) Some platform-neutral code makes "conservative" assumptions
    like handles being ints.  What about register() now?
(4) It's not yet clear (to me) what the resize story looks like.
    I ***HOPE*** we no longer need the ugly million handles.  Can
    we write a custom widget in Java?  (I mean, to implement Havoc's
    RealFixed)

(continued)

Back to the top