Logo Search packages:      
Sourcecode: blender version File versions

GHOST_WindowWin32.cpp

/**
 * $Id: GHOST_WindowWin32.cpp,v 1.10 2003/12/28 20:24:32 theeth Exp $
 * ***** 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: GHOST_WindowWin32.cpp,v 1.10 2003/12/28 20:24:32 theeth Exp $
 * Copyright (C) 2001 NaN Technologies B.V.
 * @author  Maarten Gribnau
 * @date    May 10, 2001
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#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 */
};

00082 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);
      }
}


00161 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;
      }
}

00179 bool GHOST_WindowWin32::getValid() const
{
      return m_hWnd != 0;
}


00185 void GHOST_WindowWin32::setTitle(const STR_String& title)
{
      ::SetWindowText(m_hWnd, title);
}


00191 void GHOST_WindowWin32::getTitle(STR_String& title) const
{
      char buf[s_maxTitleLength];
      ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
      STR_String temp (buf);
      title = buf;
}


00200 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;
}


00211 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;
}


00222 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;
}


00241 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;
}


00260 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;
}


00279 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;
}


00295 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;
}


00304 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;
}


00313 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_SHOWMINIMIZED; 
            break;
      case GHOST_kWindowStateMaximized: 
            ShowWindow(m_hWnd, SW_HIDE); //fe. HACK!
                        //Solves redraw problems when switching from fullscreen to normal.
                        
            wp.showCmd = SW_SHOWMAXIMIZED; 
            SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
            break;
      case GHOST_kWindowStateFullScreen:
            wp.showCmd = SW_SHOWMAXIMIZED;
            SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
            break;
      case GHOST_kWindowStateNormal: 
      default: 
            wp.showCmd = SW_SHOWNORMAL; 
            break;
      }
      return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
}


00342 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;
}


00349 GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
{
      // adding a glFinish() here is to prevent Geforce in 'full scene antialias' mode
      // from antialising the Blender window. Officially a swapbuffers does a glFinish
      // itself, so this feels really like a hack... but it won't harm. (ton)
      glFinish();
      return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
}


00359 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;
}


00377 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;
}


00390 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;
}


00440 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;
}

00465 void GHOST_WindowWin32::lostMouseCapture()
{
      if (m_hasMouseCaptured) {
            m_hasMouseCaptured = false;
            m_nPressedButtons = 0;
      }
}

00473 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;
                  }
            }
      }
}


00493 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;   break;
                  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;
                  case GHOST_kStandardCursorPencil:         id = IDC_ARROW;   break;
                  default:
                  success = false;
            }
            
            if (success) {
                  HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id));
            }
      }
}

00540 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
{
      if (::GetForegroundWindow() == m_hWnd) {
            loadCursor(visible, getCursorShape());
      }

      return GHOST_kSuccess;
}

00549 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_TUns8 */
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
{
      ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
      ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
      ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
      return ch;
}

/** 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;
}
00581 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2], 
                              GHOST_TUns8 mask[16][2], int hotX, int hotY)
{
      return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask, 
                                                      16, 16, hotX, hotY, 0, 1);
}

GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap, 
                              GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY, 
                              int fg_color, int bg_color)
{
      GHOST_TUns32 andData[32];
      GHOST_TUns32 xorData[32];
      GHOST_TUns32 fullBitRow, fullMaskRow;
      int x, y, cols;
      
      cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
      if (sizeX%8) cols++;
      
      if (m_customCursor) {
            DestroyCursor(m_customCursor);
            m_customCursor = NULL;
      }

      memset(&andData, 0xFF, sizeof(andData));
      memset(&xorData, 0, sizeof(xorData));

      for (y=0; y<sizeY; y++) {
            fullBitRow=0;
            fullMaskRow=0;
            for (x=cols-1; x>=0; x--){
                  fullBitRow<<=8;
                  fullMaskRow<<=8;
                  fullBitRow  |= uns8ReverseBits(bitmap[cols*y + x]);
                  fullMaskRow |= uns8ReverseBits(  mask[cols*y + x]);
            }
            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;
}


Generated by  Doxygen 1.6.0   Back to index