Appendix D: Spinner for Motif

This appendix contains the source code for the Motif version of the Spinner natives in spinner.c, and the shell file and makefile for building the Motif Shared Object Library libspinner.so.

spinner.c

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */
 
#include <jni.h>
#include <Xm/XmAll.h>
#include <pthread.h>
#include <stdio.h>
 
#define ARROW_WIDTH 19
#define SPACING 2
 
static jobject javaClass;
static jmethodID mid;
static pthread_key_t envKey;
 
int Callback(Widget handle, XtPointer clientData, XmAnyCallbackStruct * callData) {
    JNIEnv *env = (JNIEnv *) pthread_getspecific(envKey);
    if (env != NULL) {
        /* If an exception has already occurred,
         * allow the stack to unwind so that the
         * exception will be thrown in Java. */
        if ((*env)->ExceptionOccurred(env)) return 0;
        switch (callData->reason) {
            //case XmCR_SPIN_NEXT:
            //case XmCR_SPIN_PRIOR:
            case XmCR_OK:
                ((*env)->CallStaticVoidMethod(env, javaClass, mid, handle));
                return 0;
        }
    }
    return 0;
}

/*
 * Class:     spinner_Spinner
 * Method:    createControl
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_spinner_Spinner_createControl
    (JNIEnv *env, jclass that, jint handleParent)
{
    Widget handleSpinBox;
    Arg argList[10];
    int n = 0;
    XtSetArg(argList[n], XmNspinBoxChildType, XmNUMERIC); n++;
    XtSetArg(argList[n], XmNarrowLayout, XmARROWS_END); n++;
    handleSpinBox = XmCreateSimpleSpinBox((Widget) handleParent, NULL, argList, n);
    if (handleSpinBox == 0) return 0;
    XtManageChild(handleSpinBox);
    XtAddCallback(handleSpinBox, XmNvalueChangedCallback, (XtCallbackProc) Callback, NULL);
    if (javaClass == 0) {
        javaClass = (*env)->NewGlobalRef(env, (jobject) that);
        mid = (*env)->GetStaticMethodID(env, (jobject) that, "widgetSelected", "(I)V");
        pthread_key_create(&envKey, NULL);
    }
    pthread_setspecific(envKey, env);
    return (jint) handleSpinBox;
}

/*
 * Class:     spinner_Spinner
 * Method:    computeSize
 * Signature: (I[I)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_computeSize
    (JNIEnv *env, jclass that, jint handleSpinBox, jintArray result)
{
    Dimension width, height;
    Arg argList[10];
    int n;
    Widget handleText;
    XmFontList fontList;
    Dimension sbShadowThickness, textMarginWidth, textMarginHeight, textShadowThickness;
    int max, digits;
    char text [64];
    XmString xmString;

    jint *result1 = NULL;
    result1 = (*env)->GetIntArrayElements(env, result, NULL);

    n = 0;
    XtSetArg(argList[n], XmNtextField, &handleText); n++;
    XtSetArg(argList[n], XmNmaximumValue, &max); n++;
    XtSetArg(argList[n], XmNshadowThickness, &sbShadowThickness); n++;
    XtGetValues((Widget) handleSpinBox, argList, n);

    n = 0;
    XtSetArg(argList[n], XmNfontList, &fontList);  n++;
    XtSetArg(argList[n], XmNmarginWidth, &textMarginWidth); n++;
    XtSetArg(argList[n], XmNmarginHeight, &textMarginHeight); n++;
    XtSetArg(argList[n], XmNshadowThickness, &textShadowThickness); n++;
    XtGetValues(handleText, argList, n);

    if (max > 0) {
        digits = 0;
        while (max > 0) {
            text[digits] = '0';
            max /= 10;
            digits++;
        }
        text [digits] = 0;
        xmString = XmStringParseText(  
            (XtPointer) text,
            (XtPointer *) NULL,
            XmFONTLIST_DEFAULT_TAG, 
            XmCHARSET_TEXT, 
            (XmParseTable) NULL,
            0,
            (XtPointer) 0);
        width = XmStringWidth(fontList, xmString);
        height = XmStringHeight(fontList, xmString);
        XmStringFree(xmString);
    } else {
        width = 200;
        height = 50;
    }

    // Add in the margins.
    width += textMarginWidth * 2 + textShadowThickness * 2 + sbShadowThickness * 2 + ARROW_WIDTH + SPACING;
    height += textMarginHeight * 2 + textShadowThickness * 2 + sbShadowThickness * 2;
    result1 [0] = width;
    result1 [1] = height;
    (*env)->ReleaseIntArrayElements(env, result, result1, 0);
}

/*
 * Class:     spinner_Spinner
 * Method:    resizeControl
 * Signature: (IIIII)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_resizeControl
    (JNIEnv *env, jclass that, jint handleSpinBox, jint x, jint y, jint width, jint height)
{
    Arg arg;
    Widget handleText;
    XtSetArg(arg, XmNtextField, &handleText);
    XtGetValues((Widget) handleSpinBox, &arg, 1);
    XtResizeWidget((Widget) handleSpinBox, width, height, 0);
    XtResizeWidget(handleText, width - ARROW_WIDTH, height, 0);
}

/*
 * Class:     spinner_Spinner
 * Method:    setPosition
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_setPosition
    (JNIEnv *env, jclass that, jint handle, jint position)
{
    Arg arg;
    XtSetArg(arg, XmNposition, position);
    XtSetValues((Widget) handle, &arg, 1);
}

/*
 * Class:     spinner_Spinner
 * Method:    getPosition
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_spinner_Spinner_getPosition
    (JNIEnv *env, jclass that, jint handle)
{
    Arg arg;
    int pos;
    XtSetArg(arg, XmNposition, &pos);
    XtGetValues((Widget) handle, &arg, 1);
    return (jint) pos;
}

/*
 * Class:     spinner_Spinner
 * Method:    setMaximum
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_setMaximum
    (JNIEnv *env, jclass that, jint handle, jint max)
{
    Arg arg;
    XtSetArg(arg, XmNmaximumValue, max);
    XtSetValues((Widget) handle, &arg, 1);
}

/*
 * Class:     spinner_Spinner
 * Method:    getMaximum
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_spinner_Spinner_getMaximum
    (JNIEnv *env, jclass that, jint handle)
{
    Arg arg;
    int max;
    XtSetArg(arg, XmNmaximumValue, &max);
    XtGetValues((Widget) handle, &arg, 1);
    return (jint) max;
}

/*
 * Class:     spinner_Spinner
 * Method:    setMinimum
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_setMinimum
    (JNIEnv *env, jclass that, jint handle, jint min)
{
    Arg arg;
    XtSetArg(arg, XmNminimumValue, min);
    XtSetValues((Widget) handle, &arg, 1);
}

/*
 * Class:     spinner_Spinner
 * Method:    getMinimum
 * Signature: (I)I
 */
JNIEXPORT jint JNICALL Java_spinner_Spinner_getMinimum
    (JNIEnv *env, jclass that, jint handle)
{
    Arg arg;
    int min;
    XtSetArg(arg, XmNminimumValue, &min);
    XtGetValues((Widget) handle, &arg, 1);
    return (jint) min;
}

/*
 * Class:     spinner_Spinner
 * Method:    setFont
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_setFont
    (JNIEnv *env, jclass that, jint handle, jint fontList)
{
    Arg arg;
    Widget handleText;
    XtSetArg(arg, XmNtextField, &handleText);
    XtGetValues((Widget) handle, &arg, 1);
    XtSetArg(arg, XmNfontList, (XmFontList) fontList);
    XtSetValues(handleText, &arg, 1);
}

/*
 * Class:     spinner_Spinner
 * Method:    setFocus
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_spinner_Spinner_setFocus
    (JNIEnv *env, jclass that, jint handle)
{
    Arg arg;
    Widget handleText;
    XtSetArg(arg, XmNtextField, &handleText);
    XtGetValues((Widget) handle, &arg, 1);
    XSetInputFocus(XtDisplay(handleText), XtWindow(handleText), RevertToParent, CurrentTime);
}

build.csh

#!/bin/csh
 
setenv IVE_HOME /bluebird/teamswt/swt-builddir/ive/bin
setenv MOTIF_HOME /bluebird/teamswt/swt-builddir/motif21
setenv X_HOME /usr/X11R6
set path=($IVE_HOME $path)
setenv LD_LIBRARY_PATH .:$IVE_HOME
 
make -f makefile.mak

makefile.mak

# Makefile for module 'libspinner.so'
# assumes IVE_HOME, MOTIF_HOME, and X_HOME are set in the environment
 
# NOTE:
# We use the VPATH directive to allow the generic UNIX source files to be
# located in a single directory. IX make does not understand VPATH so
# you must use a 'make' which does understand it (like LINUX make)
VPATH= ../:../../common
 
DLLPREFIX=spinner
DLLNAME=lib$(DLLPREFIX).so
 
CFLAGS=-fpic -O -s -DLINUX -DMOTIF -I./ -I../ -I$(IVE_HOME)/include -I$(MOTIF_HOME)/include -I$(X_HOME)/include
LFLAGS=-L$(MOTIF_HOME)/lib -lXm -L/usr/lib -L/usr/X11R6/lib -rpath . -x -shared -lX11 -lm -lXext -lXt
OBJS = spinner.o
 
all: $(DLLNAME)
 
$(DLLNAME): $(OBJS)
	 ld $(LFLAGS) -o $(DLLNAME) $(OBJS)
 
clean:
	 rm -f *.o
	 rm -f $(DLLNAME)