lwjgl/src/native/win32/org_lwjgl_opengl_Display.c

555 lines
15 KiB
C
Raw Normal View History

2003-08-04 06:09:40 -04:00
/*
2004-06-12 16:28:34 -04:00
* Copyright (c) 2002-2004 LWJGL Project
2003-08-04 06:09:40 -04:00
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
2004-06-12 16:28:34 -04:00
* * Neither the name of 'LWJGL' nor the names of
2003-08-04 06:09:40 -04:00
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* $Id$
*
2004-07-03 06:16:28 -04:00
* Base Win32 display
2003-08-04 06:09:40 -04:00
*
* @author cix_foo <cix_foo@users.sourceforge.net>
* @version $Revision$
*/
#define _PRIVATE_WINDOW_H_
2004-09-22 11:06:27 -04:00
#include <windowsx.h>
2005-02-21 09:46:47 -05:00
#include <malloc.h>
#include "Window.h"
2004-07-03 10:39:29 -04:00
#include "extgl_wgl.h"
2003-10-11 12:29:40 -04:00
#include "common_tools.h"
2004-07-03 06:16:28 -04:00
#include "display.h"
2004-11-02 08:15:59 -05:00
#include "org_lwjgl_opengl_Win32Display.h"
2005-02-21 09:46:47 -05:00
#include "context.h"
2004-09-15 13:07:06 -04:00
static HWND display_hwnd = NULL; // Handle to the window
static HDC display_hdc = NULL; // Device context
static bool isFullScreen = false; // Whether we're fullscreen or not
static bool isMinimized = false; // Whether we're minimized or not
static bool isFocused = false; // whether we're focused or not
static bool isDirty = false; // Whether we're dirty or not
2004-09-15 13:07:06 -04:00
static bool isUndecorated = false; // Whether we're undecorated or not
2005-02-21 09:46:47 -05:00
static bool did_maximize = false; // A flag to tell when a window
// has recovered from minimized
2003-08-04 06:09:40 -04:00
static bool closerequested;
#define WINDOWCLASSNAME "LWJGL"
2005-04-29 11:20:19 -04:00
bool getCurrentFullscreen() {
return isFullScreen;
}
2005-02-21 09:46:47 -05:00
HDC getCurrentHDC() {
return display_hdc;
}
2004-02-15 14:24:03 -05:00
HWND getCurrentHWND() {
return display_hwnd;
}
static void setupCursorClipping() {
RECT hwnd_client;
if (display_hwnd != NULL && GetWindowRect(display_hwnd, &hwnd_client) != 0) {
if (ClipCursor(&hwnd_client) == 0)
printfDebug("ClipCursor failed\n");
}
}
static void resetDisplayModeAndClipping(JNIEnv *env) {
resetDisplayMode(env);
ClipCursor(NULL);
}
2003-08-04 06:09:40 -04:00
/*
* Called when the application is alt-tabbed to or from
*/
static void appActivate(bool active)
{
static bool inAppActivate = false;
if (inAppActivate) {
return;
}
inAppActivate = true;
2005-02-02 09:51:43 -05:00
isFocused = active;
2003-08-04 06:09:40 -04:00
if (active) {
if (isFullScreen) {
restoreDisplayMode();
}
ShowWindow(display_hwnd, SW_RESTORE);
SetForegroundWindow(display_hwnd);
2005-02-02 09:51:43 -05:00
SetFocus(display_hwnd);
2005-02-21 09:46:47 -05:00
did_maximize = true;
2003-08-04 06:09:40 -04:00
} else if (isFullScreen) {
ShowWindow(display_hwnd, SW_SHOWMINNOACTIVE);
resetDisplayModeAndClipping(NULL);
2003-08-04 06:09:40 -04:00
}
inAppActivate = false;
2003-08-04 06:09:40 -04:00
}
2005-02-21 09:46:47 -05:00
JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Win32Display_didMaximize
(JNIEnv *env, jobject self) {
jboolean result = did_maximize ? JNI_TRUE : JNI_FALSE;
did_maximize = false;
return result;
}
2003-08-04 06:09:40 -04:00
/*
* WindowProc for the GL window.
*/
LRESULT CALLBACK lwjglWindowProc(HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
2005-02-02 09:51:43 -05:00
int xPos;
int yPos;
int dwheel;
if (isFullScreen && !isMinimized && isFocused)
setupCursorClipping();
2003-08-04 06:09:40 -04:00
switch (msg) {
// disable screen saver and monitor power down messages which wreak havoc
case WM_SYSCOMMAND:
{
switch (wParam) {
case SC_KEYMENU:
case SC_MOUSEMENU:
// Ignore system menu retrieval
2003-08-04 06:09:40 -04:00
case SC_SCREENSAVE:
case SC_MONITORPOWER:
return 0L;
break;
case SC_CLOSE:
closerequested = true;
//don't continue processing this command since this
//would shutdown the window, which the application might not want to
return 0L;
}
}
break;
case WM_ACTIVATE:
switch (wParam) {
case WA_ACTIVE:
case WA_CLICKACTIVE:
appActivate(true);
break;
case WA_INACTIVE:
appActivate(false);
break;
}
return 0L;
2005-02-02 08:16:50 -05:00
case WM_SIZE:
switch (wParam) {
case SIZE_RESTORED:
case SIZE_MAXIMIZED:
isMinimized = false;
break;
case SIZE_MINIMIZED:
isMinimized = true;
break;
}
2005-02-02 09:51:43 -05:00
break;
2004-09-22 11:06:27 -04:00
case WM_MOUSEMOVE:
{
xPos = GET_X_LPARAM(lParam);
yPos = GET_Y_LPARAM(lParam);
2004-09-22 11:06:27 -04:00
handleMouseMoved(xPos, yPos);
return 0;
}
case WM_MOUSEWHEEL:
{
dwheel = GET_WHEEL_DELTA_WPARAM(wParam);
2004-09-22 11:06:27 -04:00
handleMouseScrolled(dwheel);
return 0;
}
case WM_LBUTTONDOWN:
{
handleMouseButton(0, 1);
return 0;
}
case WM_LBUTTONUP:
{
handleMouseButton(0, 0);
return 0;
}
case WM_RBUTTONDOWN:
{
handleMouseButton(1, 1);
return 0;
}
case WM_RBUTTONUP:
{
handleMouseButton(1, 0);
return 0;
}
case WM_MBUTTONDOWN:
{
handleMouseButton(2, 1);
return 0;
}
case WM_MBUTTONUP:
{
handleMouseButton(2, 0);
return 0;
}
2003-08-04 06:09:40 -04:00
break;
case WM_QUIT:
{
closerequested = true;
return 0L;
}
case WM_PAINT:
{
isDirty = true;
2003-08-04 06:09:40 -04:00
}
}
2003-08-04 06:09:40 -04:00
// default action
return DefWindowProc(hWnd, msg, wParam, lParam);
}
/*
* Handle native Win32 messages
*/
2004-09-22 11:06:27 -04:00
void handleMessages(void)
2003-08-04 06:09:40 -04:00
{
/*
* Now's our chance to deal with Windows messages that are
* otherwise just piling up and causing everything not to
* work properly
*/
MSG msg;
while (PeekMessage(
&msg, // message information
NULL, // handle to window
2003-08-04 06:09:40 -04:00
0, // first message
0, // last message
PM_REMOVE // removal options
))
{
if (display_hwnd != NULL && msg.hwnd == display_hwnd)
DispatchMessage(&msg);
2003-08-04 06:09:40 -04:00
};
}
/*
* Class: org_lwjgl_Window
* Method: nSetTitle
* Signature: ()V
*/
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_setTitle
(JNIEnv * env, jobject self, jstring title_obj)
2003-08-04 06:09:40 -04:00
{
char * title = GetStringNativeChars(env, title_obj);
SetWindowText(display_hwnd, title);
free(title);
2003-08-04 06:09:40 -04:00
}
2005-02-21 09:46:47 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_nUpdate
2004-11-02 08:15:59 -05:00
(JNIEnv * env, jobject self)
2003-08-04 06:09:40 -04:00
{
2004-09-22 11:06:27 -04:00
handleMessages();
2003-08-04 06:09:40 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Win32Display_isDirty
(JNIEnv *env, jobject self) {
bool result = isDirty;
isDirty = false;
return result ? JNI_TRUE : JNI_FALSE;
2003-08-04 06:09:40 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Win32Display_isVisible
(JNIEnv *env, jobject self) {
return isMinimized ? JNI_FALSE : JNI_TRUE;
2003-08-04 06:09:40 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Win32Display_isCloseRequested
(JNIEnv *env, jobject self) {
2003-08-04 06:09:40 -04:00
bool saved = closerequested;
closerequested = false;
return saved;
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jboolean JNICALL Java_org_lwjgl_opengl_Win32Display_isActive
(JNIEnv *env, jobject self) {
return isFocused;
2003-08-04 06:09:40 -04:00
}
2003-10-20 10:17:47 -04:00
2004-11-02 08:15:59 -05:00
JNIEXPORT jobjectArray JNICALL Java_org_lwjgl_opengl_Win32Display_getAvailableDisplayModes(JNIEnv *env, jobject self) {
2004-07-03 06:16:28 -04:00
return getAvailableDisplayModes(env);
}
2005-02-21 09:46:47 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_nCreateWindow(JNIEnv *env, jobject self, jobject mode, jboolean fullscreen, jint x, jint y) {
jclass cls_displayMode = (*env)->GetObjectClass(env, mode);
jfieldID fid_width = (*env)->GetFieldID(env, cls_displayMode, "width", "I");
jfieldID fid_height = (*env)->GetFieldID(env, cls_displayMode, "height", "I");
int width = (*env)->GetIntField(env, mode, fid_width);
int height = (*env)->GetIntField(env, mode, fid_height);
BOOL result;
static bool oneShotInitialised = false;
if (!oneShotInitialised) {
if (!registerWindow(lwjglWindowProc, WINDOWCLASSNAME)) {
throwException(env, "Could not register window class");
return;
}
oneShotInitialised = true;
}
2004-07-03 06:16:28 -04:00
closerequested = false;
isMinimized = false;
isFocused = false;
2004-07-03 06:16:28 -04:00
isDirty = true;
isFullScreen = fullscreen == JNI_TRUE;
isUndecorated = getBooleanProperty(env, "org.lwjgl.opengl.Window.undecorated");
2005-02-21 09:46:47 -05:00
display_hwnd = createWindow(WINDOWCLASSNAME, x, y, width, height, isFullScreen, isUndecorated);
if (display_hwnd == NULL) {
throwException(env, "Failed to create the window.");
2004-07-03 06:16:28 -04:00
return;
}
display_hdc = GetDC(display_hwnd);
ShowWindow(display_hwnd, SW_SHOWDEFAULT);
UpdateWindow(display_hwnd);
SetForegroundWindow(display_hwnd);
SetFocus(display_hwnd);
2004-07-03 06:16:28 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_destroyWindow(JNIEnv *env, jobject self) {
2005-01-29 05:17:56 -05:00
closeWindow(&display_hwnd, &display_hdc);
if (isFullScreen)
ClipCursor(NULL);
2004-07-03 06:16:28 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_switchDisplayMode(JNIEnv *env, jobject self, jobject mode) {
2004-07-03 06:16:28 -04:00
switchDisplayMode(env, mode);
}
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_resetDisplayMode(JNIEnv *env, jobject self) {
resetDisplayModeAndClipping(env);
2004-07-03 06:16:28 -04:00
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Win32Display_getGammaRampLength(JNIEnv *env, jobject self) {
2004-07-03 06:16:28 -04:00
return getGammaRampLength();
}
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_setGammaRamp(JNIEnv *env, jobject self, jobject gamma_buffer) {
2004-07-03 06:16:28 -04:00
setGammaRamp(env, gamma_buffer);
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jstring JNICALL Java_org_lwjgl_opengl_Win32Display_getVersion(JNIEnv *env, jobject self) {
2004-07-03 06:16:28 -04:00
return getVersion(env);
}
2004-11-02 08:15:59 -05:00
JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_Win32Display_init(JNIEnv *env, jobject self) {
2004-07-03 06:16:28 -04:00
return initDisplay(env);
}
2004-11-02 08:15:59 -05:00
JNIEXPORT void JNICALL Java_org_lwjgl_opengl_Win32Display_reshape(JNIEnv *env, jobject self, jint x, jint y, jint width, jint height) {
2005-04-29 11:08:16 -04:00
DWORD exstyle, windowflags;
2005-02-21 09:46:47 -05:00
RECT clientSize;
2004-09-15 13:07:06 -04:00
if (isFullScreen) {
return;
}
2005-04-29 11:20:19 -04:00
getWindowFlags(&windowflags, &exstyle, isFullScreen, getBooleanProperty(env, "org.lwjgl.opengl.Window.undecorated"));
2004-09-15 13:07:06 -04:00
// If we're not a fullscreen window, adjust the height to account for the
// height of the title bar:
clientSize.bottom = height;
clientSize.left = 0;
clientSize.right = width;
clientSize.top = 0;
AdjustWindowRectEx(
&clientSize, // client-rectangle structure
windowflags, // window styles
FALSE, // menu-present option
exstyle // extended window style
);
SetWindowPos(display_hwnd, HWND_TOP, x, y, clientSize.right - clientSize.left, clientSize.bottom - clientSize.top, SWP_NOZORDER);
}
static HICON createWindowIcon(JNIEnv *env, jint *pixels, jint width, jint height) {
unsigned char col;
unsigned char mask;
BITMAPINFO bitmapInfo;
HBITMAP cursorMask;
HBITMAP colorBitmap;
ICONINFO iconInfo;
HICON icon;
char *ptrCursorImage;
int x, y;
char *dstPtr;
int pixelCount;
int scanlinePad;
int wordAlignedWidth;
int imageSize;
unsigned char *maskPixels;
int widthInBytes;
int leftShift;
int maskPixelsOff;
int scanlineWidth;
HBITMAP colorDIB;
jsize pixelsLen = width * height;
memset(&bitmapInfo, 0, sizeof(BITMAPINFO));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = width;
bitmapInfo.bmiHeader.biHeight = -height;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 24;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
colorDIB = CreateDIBSection(GetDC(NULL), (BITMAPINFO*)&(bitmapInfo),
DIB_RGB_COLORS, (void**)&(ptrCursorImage), NULL, 0);
if (!ptrCursorImage) {
throwException(env, "Could not allocate DIB section.");
}
wordAlignedWidth = width * 3;
if (wordAlignedWidth % sizeof(long) != 0) {
wordAlignedWidth = (wordAlignedWidth / sizeof(long)) * sizeof(long) + sizeof(long);
}
for (y = 0; y < height; y++ ) {
dstPtr = ptrCursorImage + wordAlignedWidth*y;;
for (x = 0; x < width; x++ ) {
2005-07-16 07:27:58 -04:00
if ((pixels[y*width+x] & 0xFF000000) != 0)
{
dstPtr[0] = (pixels[y*width+x] >> 0x10) & 0xFF;
dstPtr[1] = (pixels[y*width+x] >> 0x08) & 0xFF;
dstPtr[2] = pixels[y*width+x] & 0xFF;
}
else
{
dstPtr[0] = 0;
dstPtr[1] = 0;
dstPtr[2] = 0;
}
dstPtr += 3;
}
}
colorBitmap = CreateDIBitmap(GetDC(NULL),
(BITMAPINFOHEADER*)&bitmapInfo.bmiHeader,
CBM_INIT,
(void *)ptrCursorImage,
(BITMAPINFO*)&bitmapInfo,
DIB_RGB_COLORS);
DeleteObject(colorDIB);
// Convert alpha map to pixel packed mask
// number of bytes it takes to fit a bit packed scan line.
widthInBytes = (width & 0x7) != 0 ? (width >> 3) + 1 : (width >> 3);
// number of bytes it takes to fit WORD padded scan line.
scanlineWidth = widthInBytes;
if (scanlineWidth % sizeof(WORD) != 0) {
scanlineWidth = (scanlineWidth / sizeof(WORD)) * sizeof(WORD) + sizeof(WORD);
}
imageSize = scanlineWidth*height;
maskPixels = (unsigned char*)malloc(sizeof(unsigned char)*imageSize);
memset(maskPixels, 0, imageSize);
2005-07-16 06:30:16 -04:00
for (y = 0; y < height; y++) {
leftShift = 7;
mask = 0;
maskPixelsOff = scanlineWidth*y;
for (x = 0; x < width; x++) {
2005-07-16 07:27:58 -04:00
col = (((pixels[(width*y)+x] & 0xFF000000) != 0) ? 1 : 0) << leftShift;
mask = mask | col;
leftShift--;
if (leftShift == -1) {
maskPixels[maskPixelsOff++] = ~mask;
leftShift = 7;
mask = 0;
}
}
// write what is left over
if (leftShift != 7) {
maskPixels[maskPixelsOff++] = ~mask;
}
}
2005-07-16 06:30:16 -04:00
cursorMask = CreateBitmap(width, height, 1, 1, maskPixels);
memset(&iconInfo, 0, sizeof(ICONINFO));
iconInfo.hbmMask = cursorMask;
iconInfo.hbmColor = colorBitmap;
iconInfo.fIcon = TRUE;
iconInfo.xHotspot = 0;
iconInfo.yHotspot = 0;
icon = CreateIconIndirect(&iconInfo);
DeleteObject(colorBitmap);
DeleteObject(cursorMask);
free(maskPixels);
return icon;
}
JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Win32Display_nSetWindowIcon16
(JNIEnv *env, jclass clazz, jobject iconBuffer)
{
int *imgData = (int *)(*env)->GetDirectBufferAddress(env, iconBuffer);
HICON newIcon = createWindowIcon(env, imgData, 16, 16);
if (newIcon != NULL) {
if (display_hwnd != NULL) {
SendMessage(display_hwnd, WM_SETICON, ICON_SMALL, (LPARAM) (newIcon));
return 0;
}
}
return -1;
}
JNIEXPORT jint JNICALL Java_org_lwjgl_opengl_Win32Display_nSetWindowIcon32
(JNIEnv *env, jclass clazz, jobject iconBuffer)
{
int *imgData = (int *)(*env)->GetDirectBufferAddress(env, iconBuffer);
HICON newIcon = createWindowIcon(env, imgData, 32, 32);
if (newIcon != NULL) {
if (display_hwnd != NULL) {
SendMessage(display_hwnd, WM_SETICON, ICON_BIG, (LPARAM) (newIcon));
return 0;
}
}
return -1;
}