Appendix C: Spinner for Windows
This appendix contains the source code for the Windows version of the Spinner natives in spinner.c, and the batch file and makefile for building the Windows Dynamic Link Library
spinner.dll.
spinner.c
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
#include <jni.h>
#include <windows.h>
#include <commctrl.h>
static DWORD tlsIndex = 0;
static jobject javaClass;
static jmethodID mid;
static WNDPROC oldProc;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
JNIEnv *env = TlsGetValue(tlsIndex);
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 (msg) {
case WM_VSCROLL:
if ((wParam & 0xFFFF) == SB_THUMBPOSITION) {
((*env)->CallStaticVoidMethod(env, javaClass, mid, lParam));
return (LRESULT) 0;
}
break;
}
}
return CallWindowProc(oldProc, hwnd, msg, wParam, lParam);
}
/*
* Class: spinner_Spinner
* Method: createControl
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_spinner_Spinner_createControl
(JNIEnv *env, jclass that, jint hwndParent)
{
HWND hwndText, hwndUpDown;
if (tlsIndex == 0) {
tlsIndex = TlsAlloc();
if (tlsIndex == -1) return (jint) 0;
javaClass = (*env)->NewGlobalRef(env, (jobject) that);
mid = (*env)->GetStaticMethodID(env, (jobject) that, "widgetSelected", "(I)V");
oldProc = (WNDPROC) GetWindowLong((HWND) hwndParent, GWL_WNDPROC);
}
TlsSetValue(tlsIndex, (LPVOID) env);
hwndText = CreateWindowEx(
WS_EX_CLIENTEDGE,
"EDIT",
NULL,
WS_CHILD | WS_VISIBLE | WS_TABSTOP,
0, 0, 0, 0,
(HWND) hwndParent,
0,
GetModuleHandle(NULL),
NULL);
if (hwndText == 0) return (jint) 0;
hwndUpDown = CreateWindowEx(
0,
UPDOWN_CLASS,
NULL,
WS_CHILD | WS_VISIBLE | UDS_AUTOBUDDY | UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,
0, 0, 0, 0,
(HWND) hwndParent,
0,
GetModuleHandle(NULL),
NULL);
if (hwndUpDown == 0) return (jint) 0;
SetWindowLong((HWND) hwndParent, GWL_WNDPROC, (long) WindowProc);
return (jint) hwndUpDown;
}
/*
* Class: spinner_Spinner
* Method: computeSize
* Signature: (I[I)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_computeSize
(JNIEnv *env, jclass that, jint hwndUpDown, jintArray result) {
int width, height;
TEXTMETRIC tm;
RECT rect;
int comboHeight;
int max, digits;
UINT flags;
char text[64];
HWND hwndText = (HWND) SendMessage((HWND) hwndUpDown, UDM_GETBUDDY, 0, 0);
HDC hDC = GetDC(hwndText);
HFONT oldFont = 0;
HFONT newFont = (HFONT) SendMessage(hwndText, WM_GETFONT, 0, 0);
jint *result1 = NULL;
result1 = (*env)->GetIntArrayElements(env, result, NULL);
if (newFont != 0) oldFont = SelectObject(hDC, newFont);
GetTextMetrics(hDC, &tm);
comboHeight = GetSystemMetrics(SM_CYVSCROLL);
height = (comboHeight > tm.tmHeight) ? comboHeight : tm.tmHeight;
max = SendMessage((HWND) hwndUpDown, UDM_GETRANGE, 0, 0) & 0xFFFF;
if (max > 0) {
digits = 0;
while (max > 0) {
text[digits] = '0';
max /= 10;
digits++;
}
flags = DT_CALCRECT | DT_EDITCONTROL | DT_NOPREFIX;
DrawText(hDC, (LPCTSTR) text, digits, (LPRECT) &rect, flags);
width = rect.right - rect.left + 3;
} else {
width = 10;
}
if (newFont != 0) SelectObject(hDC, oldFont);
ReleaseDC(hwndText, hDC);
width += GetSystemMetrics(SM_CXVSCROLL);
SendMessage(hwndText, EM_GETRECT, 0, (LPARAM) &rect);
if (rect.top == 0) rect.top = 1; // windows bug fix
width += (rect.left + 1) * 2;
height += (rect.top + 1) * 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 hwndUpDown, jint x, jint y, jint width, jint height)
{
HWND hwndText = (HWND) SendMessage((HWND) hwndUpDown, UDM_GETBUDDY, 0, 0);
UINT flags = SWP_NOZORDER | SWP_DRAWFRAME | SWP_NOACTIVATE;
int upDownWidth = GetSystemMetrics(SM_CXVSCROLL);
SetWindowPos(hwndText, (HWND) 0, x, y, width - upDownWidth + 2, height, flags);
SetWindowPos((HWND) hwndUpDown, (HWND) 0, x + width - upDownWidth, y, upDownWidth, height, flags);
}
/*
* Class: spinner_Spinner
* Method: setPosition
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_setPosition
(JNIEnv *env, jclass that, jint hwnd, jint position)
{
SendMessage((HWND) hwnd, UDM_SETPOS, 0, position);
}
/*
* Class: spinner_Spinner
* Method: getPosition
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_spinner_Spinner_getPosition
(JNIEnv *env, jclass that, jint hwnd)
{
return (jint) SendMessage((HWND) hwnd, UDM_GETPOS, 0, 0) & 0xFFFF;
}
/*
* Class: spinner_Spinner
* Method: setMaximum
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_setMaximum
(JNIEnv *env, jclass that, jint hwnd, jint max)
{
int min = SendMessage((HWND) hwnd, UDM_GETRANGE, 0, 0) >> 16;
SendMessage((HWND) hwnd, UDM_SETRANGE, 0, (min << 16) | max);
}
/*
* Class: spinner_Spinner
* Method: getMaximum
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_spinner_Spinner_getMaximum
(JNIEnv *env, jclass that, jint hwnd)
{
return SendMessage((HWND) hwnd, UDM_GETRANGE, 0, 0) & 0xFFFF;
}
/*
* Class: spinner_Spinner
* Method: setMinimum
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_setMinimum
(JNIEnv *env, jclass that, jint hwnd, jint min)
{
int max = SendMessage((HWND) hwnd, UDM_GETRANGE, 0, 0) & 0xFFFF;
SendMessage((HWND) hwnd, UDM_SETRANGE, 0, (min << 16) | max);
}
/*
* Class: spinner_Spinner
* Method: getMinimum
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_spinner_Spinner_getMinimum
(JNIEnv *env, jclass that, jint hwnd)
{
return SendMessage((HWND) hwnd, UDM_GETRANGE, 0, 0) >> 16;
}
/*
* Class: spinner_Spinner
* Method: setFont
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_setFont
(JNIEnv *env, jclass that, jint hwnd, jint hFont)
{
HWND hwndText = (HWND) SendMessage((HWND) hwnd, UDM_GETBUDDY, 0, 0);
SendMessage(hwndText, WM_SETFONT, hFont, 1);
}
/*
* Class: spinner_Spinner
* Method: setFocus
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_spinner_Spinner_setFocus
(JNIEnv *env, jclass that, jint hwnd)
{
HWND hwndText = (HWND) SendMessage((HWND) hwnd, UDM_GETBUDDY, 0, 0);
SetFocus(hwndText);
}
build.bat
@echo off
IF NOT "%IVE_HOME%"=="" GOTO MAKE
set IVE_HOME=j:\teamswt\swt-builddir\ive\bin
set path=%IVE_HOME%;%path%
rem NOTE:
rem Initialize MSVC 6.0/MSSDK environment
call k:\dev\products\msvc60\vc98\bin\vcvars32.bat
set Mssdk=j:\teamswt\swt-builddir\mssdk
call %Mssdk%\setenv.bat
:MAKE
nmake makefile.mak
makefile.mak
# Makefile for module 'spinner.dll'
# assumes IVE_HOME is set in the environment from which nmake is run
!include <win32.mak>
DLLPREFIX=spinner
DLLNAME=$(DLLPREFIX).dll
CFLAGS=-c -W3 -G6 -GD -O1 -nologo -D_X86_=1 -D_WIN32 -D_WIN95 -D_WIN32_WINDOWS=0x0400 -D_MT -MT -DWIN32 -D_WIN32_DCOM /I$(IVE_HOME)\include /I.
LFLAGS=/INCREMENTAL:NO /PDB:NONE /RELEASE /NOLOGO /BASE:0x10000000 /DLL
LINK_LIBS=comctl32.lib user32.lib gdi32.lib
OBJS=$(DLLPREFIX).obj
all: $(OBJS) $(DLLPREFIX)
$(DLLPREFIX): $(OBJS)
echo $(LINK_LIBS) >templrf
echo $(LFLAGS) >>templrf
echo -machine:IX86 >>templrf
echo -subsystem:windows >>templrf
echo -out:$(DLLNAME) >>templrf
echo $(OBJS) >>templrf
link @templrf
del templrf
clean:
del *.obj
del *.dll
del *.exp
.c.obj:
cl $(CFLAGS) $*.c