diff options
Diffstat (limited to 'intern/ghost/intern/GHOST_WindowWin32.cpp')
-rw-r--r-- | intern/ghost/intern/GHOST_WindowWin32.cpp | 584 |
1 files changed, 584 insertions, 0 deletions
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp new file mode 100644 index 00000000000..239a020083b --- /dev/null +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -0,0 +1,584 @@ +/** + * $Id$ + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/** + + * $Id$ + * Copyright (C) 2001 NaN Technologies B.V. + * @author Maarten Gribnau + * @date May 10, 2001 + */ + +#include <string.h> + +#include "GHOST_WindowWin32.h" + +#include <GL/gl.h> + +LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass"; +const int GHOST_WindowWin32::s_maxTitleLength = 128; +HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL; + +/* + * Color and depth bit values are not to be trusted. + * For instance, on TNT2: + * When the screen color depth is set to 16 bit, we get 5 color bits + * and 16 depth bits. + * When the screen color depth is set to 32 bit, we get 8 color bits + * and 24 depth bits. + * Just to be safe, we request high waulity settings. + */ +static PIXELFORMATDESCRIPTOR sPreferredFormat = { + sizeof(PIXELFORMATDESCRIPTOR), /* size */ + 1, /* version */ + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_DOUBLEBUFFER, /* support double-buffering */ + PFD_TYPE_RGBA, /* color type */ + 32, /* prefered color depth */ + 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ + 0, /* no alpha buffer */ + 0, /* alpha bits (ignored) */ + 0, /* no accumulation buffer */ + 0, 0, 0, 0, /* accum bits (ignored) */ + 32, /* depth buffer */ + 0, /* no stencil buffer */ + 0, /* no auxiliary buffers */ + PFD_MAIN_PLANE, /* main layer */ + 0, /* reserved */ + 0, 0, 0 /* no layer, visible, damage masks */ +}; + +GHOST_WindowWin32::GHOST_WindowWin32( + const STR_String& title, + GHOST_TInt32 left, + GHOST_TInt32 top, + GHOST_TUns32 width, + GHOST_TUns32 height, + GHOST_TWindowState state, + GHOST_TDrawingContextType type, + const bool stereoVisual) +: + GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone, + stereoVisual), + m_hDC(0), + m_hGlRc(0), + m_hasMouseCaptured(false), + m_nPressedButtons(0), + m_customCursor(0) +{ + if (state != GHOST_kWindowStateFullScreen) { + /* Convert client size into window size */ + width += GetSystemMetrics(SM_CXSIZEFRAME)*2; + height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION); + + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_OVERLAPPEDWINDOW, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + else { + m_hWnd = ::CreateWindow( + s_windowClassName, // pointer to registered class name + title, // pointer to window name + WS_POPUP | WS_MAXIMIZE, // window style + left, // horizontal position of window + top, // vertical position of window + width, // window width + height, // window height + 0, // handle to parent or owner window + 0, // handle to menu or child-window identifier + ::GetModuleHandle(0), // handle to application instance + 0); // pointer to window-creation data + } + if (m_hWnd) { + // Store a pointer to this class in the window structure + LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this); + + // Store the device context + m_hDC = ::GetDC(m_hWnd); + + // Show the window + int nCmdShow; + switch (state) { + case GHOST_kWindowStateMaximized: + nCmdShow = SW_SHOWMAXIMIZED; + break; + case GHOST_kWindowStateMinimized: + nCmdShow = SW_SHOWMINIMIZED; + break; + case GHOST_kWindowStateNormal: + default: + nCmdShow = SW_SHOWNORMAL; + break; + } + setDrawingContextType(type); + ::ShowWindow(m_hWnd, nCmdShow); + // Force an initial paint of the window + ::UpdateWindow(m_hWnd); + } +} + + +GHOST_WindowWin32::~GHOST_WindowWin32() +{ + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + setDrawingContextType(GHOST_kDrawingContextTypeNone); + if (m_hDC) { + ::ReleaseDC(m_hWnd, m_hDC); + m_hDC = 0; + } + if (m_hWnd) { + ::DestroyWindow(m_hWnd); + m_hWnd = 0; + } +} + +bool GHOST_WindowWin32::getValid() const +{ + return m_hWnd != 0; +} + + +void GHOST_WindowWin32::setTitle(const STR_String& title) +{ + ::SetWindowText(m_hWnd, title); +} + + +void GHOST_WindowWin32::getTitle(STR_String& title) const +{ + char buf[s_maxTitleLength]; + ::GetWindowText(m_hWnd, buf, s_maxTitleLength); + STR_String temp (buf); + title = buf; +} + + +void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetWindowRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const +{ + RECT rect; + ::GetClientRect(m_hWnd, &rect); + bounds.m_b = rect.bottom; + bounds.m_l = rect.left; + bounds.m_r = rect.right; + bounds.m_t = rect.top; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getWidth() != width) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if (cBnds.getHeight() != height) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height) +{ + GHOST_TSuccess success; + GHOST_Rect cBnds, wBnds; + getClientBounds(cBnds); + if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) { + getWindowBounds(wBnds); + int cx = wBnds.getWidth() + width - cBnds.getWidth(); + int cy = wBnds.getHeight() + height - cBnds.getHeight(); + success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ? + GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TWindowState GHOST_WindowWin32::getState() const +{ + GHOST_TWindowState state; + if (::IsIconic(m_hWnd)) { + state = GHOST_kWindowStateMinimized; + } + else if (::IsZoomed(m_hWnd)) { + state = GHOST_kWindowStateMaximized; + } + else { + state = GHOST_kWindowStateNormal; + } + return state; +} + + +void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ScreenToClient(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const +{ + POINT point = { inX, inY }; + ::ClientToScreen(m_hWnd, &point); + outX = point.x; + outY = point.y; +} + + +GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state) +{ + WINDOWPLACEMENT wp; + wp.length = sizeof(WINDOWPLACEMENT); + ::GetWindowPlacement(m_hWnd, &wp); + switch (state) { + case GHOST_kWindowStateMinimized: wp.showCmd = SW_SHOWMAXIMIZED; break; + case GHOST_kWindowStateMaximized: wp.showCmd = SW_SHOWMINIMIZED; break; + case GHOST_kWindowStateNormal: default: wp.showCmd = SW_SHOWNORMAL; break; + } + return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order) +{ + HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM; + return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::swapBuffers() +{ + return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure; +} + + +GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext() +{ + GHOST_TSuccess success; + if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { + if (m_hDC && m_hGlRc) { + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + else { + success = GHOST_kSuccess; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::invalidate() +{ + GHOST_TSuccess success; + if (m_hWnd) { + success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type) +{ + GHOST_TSuccess success; + switch (type) { + case GHOST_kDrawingContextTypeOpenGL: + { + if(m_stereoVisual) + sPreferredFormat.dwFlags |= PFD_STEREO; + + // Attempt to match device context pixel format to the preferred format + int iPixelFormat = ::ChoosePixelFormat(m_hDC, &sPreferredFormat); + if (iPixelFormat == 0) { + success = GHOST_kFailure; + break; + } + if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) { + success = GHOST_kFailure; + break; + } + // For debugging only: retrieve the pixel format chosen + PIXELFORMATDESCRIPTOR preferredFormat; + ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat); + // Create the context + m_hGlRc = ::wglCreateContext(m_hDC); + if (m_hGlRc) { + if (s_firsthGLRc) { + wglShareLists(s_firsthGLRc, m_hGlRc); + } else { + s_firsthGLRc = m_hGlRc; + } + + success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + } + else { + success = GHOST_kFailure; + } + } + break; + + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + + default: + success = GHOST_kFailure; + } + return success; +} + + +GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext() +{ + GHOST_TSuccess success; + switch (m_drawingContextType) { + case GHOST_kDrawingContextTypeOpenGL: + if (m_hGlRc) { + success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure; + if (m_hGlRc == s_firsthGLRc) { + s_firsthGLRc = NULL; + } + m_hGlRc = 0; + } + else { + success = GHOST_kFailure; + } + break; + case GHOST_kDrawingContextTypeNone: + success = GHOST_kSuccess; + break; + default: + success = GHOST_kFailure; + } + return success; +} + +void GHOST_WindowWin32::lostMouseCapture() +{ + if (m_hasMouseCaptured) { + m_hasMouseCaptured = false; + m_nPressedButtons = 0; + } +} + +void GHOST_WindowWin32::registerMouseClickEvent(bool press) +{ + if (press) { + if (!m_hasMouseCaptured) { + ::SetCapture(m_hWnd); + m_hasMouseCaptured = true; + } + m_nPressedButtons++; + } else { + if (m_nPressedButtons) { + m_nPressedButtons--; + if (!m_nPressedButtons) { + ::ReleaseCapture(); + m_hasMouseCaptured = false; + } + } + } +} + + +void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const +{ + if (!visible) { + while (::ShowCursor(FALSE) >= 0); + } + else { + while (::ShowCursor(TRUE) < 0); + } + + if (cursor == GHOST_kStandardCursorCustom && m_customCursor) { + ::SetCursor( m_customCursor ); + } else { + // Convert GHOST cursor to Windows OEM cursor + bool success = true; + LPCSTR id; + switch (cursor) { + case GHOST_kStandardCursorDefault: id = IDC_ARROW; + case GHOST_kStandardCursorRightArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorLeftArrow: id = IDC_ARROW; break; + case GHOST_kStandardCursorInfo: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorDestroy: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorHelp: id = IDC_HELP; break; // Arrow and question mark + case GHOST_kStandardCursorCycle: id = IDC_NO; break; // Slashed circle + case GHOST_kStandardCursorSpray: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west + case GHOST_kStandardCursorWait: id = IDC_WAIT; break; // Hourglass + case GHOST_kStandardCursorText: id = IDC_IBEAM; break; // I-beam + case GHOST_kStandardCursorCrosshair: id = IDC_CROSS; break; // Crosshair + case GHOST_kStandardCursorUpDown: id = IDC_SIZENS; break; // Double-pointed arrow pointing north and south + case GHOST_kStandardCursorLeftRight: id = IDC_SIZEWE; break; // Double-pointed arrow pointing west and east + case GHOST_kStandardCursorTopSide: id = IDC_UPARROW; break; // Vertical arrow + case GHOST_kStandardCursorBottomSide: id = IDC_SIZENS; break; + case GHOST_kStandardCursorLeftSide: id = IDC_SIZEWE; break; + case GHOST_kStandardCursorTopLeftCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorTopRightCorner: id = IDC_SIZENESW; break; + case GHOST_kStandardCursorBottomRightCorner: id = IDC_SIZENWSE; break; + case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW; break; + default: + success = false; + } + + if (success) { + HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id)); + } + } +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible) +{ + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(visible, getCursorShape()); + } + + return GHOST_kSuccess; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape) +{ + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), cursorShape); + } + + return GHOST_kSuccess; +} + +/** Reverse the bits in a GHOST_TUns16 */ +static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt) +{ + shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA); + shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC); + shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0); + shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00); + return shrt; +} + +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], GHOST_TUns8 mask[16][2], int hotX, int hotY) +{ + GHOST_TUns32 andData[32]; + GHOST_TUns32 xorData[32]; + int y; + + if (m_customCursor) { + DestroyCursor(m_customCursor); + m_customCursor = NULL; + } + + memset(&andData, 0xFF, sizeof(andData)); + memset(&xorData, 0, sizeof(xorData)); + + for (y=0; y<16; y++) { + GHOST_TUns32 fullBitRow = uns16ReverseBits((bitmap[y][0]<<8) | (bitmap[y][1]<<0)); + GHOST_TUns32 fullMaskRow = uns16ReverseBits((mask[y][0]<<8) | (mask[y][1]<<0)); + + xorData[y]= fullBitRow & fullMaskRow; + andData[y]= ~fullMaskRow; + } + + m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData); + if (!m_customCursor) { + return GHOST_kFailure; + } + + if (::GetForegroundWindow() == m_hWnd) { + loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom); + } + + return GHOST_kSuccess; +} + |