2
* $Id: GHOST_WindowWin32.cpp 17019 2008-10-11 16:03:17Z blendix $
3
* ***** BEGIN GPL LICENSE BLOCK *****
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License
7
* as published by the Free Software Foundation; either version 2
8
* of the License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software Foundation,
17
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20
* All rights reserved.
22
* The Original Code is: all of this file.
24
* Contributor(s): none yet.
26
* ***** END GPL LICENSE BLOCK *****
31
* $Id: GHOST_WindowWin32.cpp 17019 2008-10-11 16:03:17Z blendix $
32
* Copyright (C) 2001 NaN Technologies B.V.
33
* @author Maarten Gribnau
42
#include "GHOST_WindowWin32.h"
46
// MSVC6 still doesn't define M_PI
48
#define M_PI 3.1415926536
51
// win64 doesn't define GWL_USERDATA
54
#define GWL_USERDATA GWLP_USERDATA
55
#define GWL_WNDPROC GWLP_WNDPROC
59
LPCSTR GHOST_WindowWin32::s_windowClassName = "GHOST_WindowClass";
60
const int GHOST_WindowWin32::s_maxTitleLength = 128;
61
HGLRC GHOST_WindowWin32::s_firsthGLRc = NULL;
63
static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd);
64
static int EnumPixelFormats(HDC hdc);
67
* Color and depth bit values are not to be trusted.
68
* For instance, on TNT2:
69
* When the screen color depth is set to 16 bit, we get 5 color bits
71
* When the screen color depth is set to 32 bit, we get 8 color bits
73
* Just to be safe, we request high waulity settings.
75
static PIXELFORMATDESCRIPTOR sPreferredFormat = {
76
sizeof(PIXELFORMATDESCRIPTOR), /* size */
80
PFD_SWAP_COPY | /* support swap copy */
81
PFD_DOUBLEBUFFER, /* support double-buffering */
82
PFD_TYPE_RGBA, /* color type */
83
32, /* prefered color depth */
84
0, 0, 0, 0, 0, 0, /* color bits (ignored) */
85
0, /* no alpha buffer */
86
0, /* alpha bits (ignored) */
87
0, /* no accumulation buffer */
88
0, 0, 0, 0, /* accum bits (ignored) */
89
32, /* depth buffer */
90
0, /* no stencil buffer */
91
0, /* no auxiliary buffers */
92
PFD_MAIN_PLANE, /* main layer */
94
0, 0, 0 /* no layer, visible, damage masks */
97
GHOST_WindowWin32::GHOST_WindowWin32(
98
const STR_String& title,
103
GHOST_TWindowState state,
104
GHOST_TDrawingContextType type,
105
const bool stereoVisual)
107
GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone,
111
m_hasMouseCaptured(false),
112
m_nPressedButtons(0),
119
if (state != GHOST_kWindowStateFullScreen) {
120
/* Convert client size into window size */
121
width += GetSystemMetrics(SM_CXSIZEFRAME)*2;
122
height += GetSystemMetrics(SM_CYSIZEFRAME)*2 + GetSystemMetrics(SM_CYCAPTION);
124
m_hWnd = ::CreateWindow(
125
s_windowClassName, // pointer to registered class name
126
title, // pointer to window name
127
WS_OVERLAPPEDWINDOW, // window style
128
left, // horizontal position of window
129
top, // vertical position of window
130
width, // window width
131
height, // window height
132
0, // handle to parent or owner window
133
0, // handle to menu or child-window identifier
134
::GetModuleHandle(0), // handle to application instance
135
0); // pointer to window-creation data
138
m_hWnd = ::CreateWindow(
139
s_windowClassName, // pointer to registered class name
140
title, // pointer to window name
141
WS_POPUP | WS_MAXIMIZE, // window style
142
left, // horizontal position of window
143
top, // vertical position of window
144
width, // window width
145
height, // window height
146
0, // handle to parent or owner window
147
0, // handle to menu or child-window identifier
148
::GetModuleHandle(0), // handle to application instance
149
0); // pointer to window-creation data
152
// Store a pointer to this class in the window structure
153
LONG result = ::SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this);
155
// Store the device context
156
m_hDC = ::GetDC(m_hWnd);
161
case GHOST_kWindowStateMaximized:
162
nCmdShow = SW_SHOWMAXIMIZED;
164
case GHOST_kWindowStateMinimized:
165
nCmdShow = SW_SHOWMINIMIZED;
167
case GHOST_kWindowStateNormal:
169
nCmdShow = SW_SHOWNORMAL;
172
setDrawingContextType(type);
173
::ShowWindow(m_hWnd, nCmdShow);
174
// Force an initial paint of the window
175
::UpdateWindow(m_hWnd);
178
m_wintab = ::LoadLibrary("Wintab32.dll");
180
GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
181
GHOST_WIN32_WTOpen fpWTOpen = ( GHOST_WIN32_WTOpen ) ::GetProcAddress( m_wintab, "WTOpenA" );
183
// let's see if we can initialize tablet here
184
/* check if WinTab available. */
185
if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
186
// Now init the tablet
188
AXIS TabletX, TabletY, Pressure, Orientation[3]; /* The maximum tablet size, pressure and orientation (tilt) */
190
// Open a Wintab context
192
// Get default context information
193
fpWTInfo( WTI_DEFCONTEXT, 0, &lc );
196
lc.lcPktData = PACKETDATA;
197
lc.lcPktMode = PACKETMODE;
198
lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
200
/* Set the entire tablet as active */
201
fpWTInfo(WTI_DEVICES,DVC_X,&TabletX);
202
fpWTInfo(WTI_DEVICES,DVC_Y,&TabletY);
204
/* get the max pressure, to divide into a float */
205
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
207
m_maxPressure = Pressure.axMax;
211
/* get the max tilt axes, to divide into floats */
212
BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
214
/* does the tablet support azimuth ([0]) and altitude ([1]) */
215
if (Orientation[0].axResolution && Orientation[1].axResolution) {
216
/* all this assumes the minimum is 0 */
217
m_maxAzimuth = Orientation[0].axMax;
218
m_maxAltitude = Orientation[1].axMax;
220
else { /* no so dont do tilt stuff */
221
m_maxAzimuth = m_maxAltitude = 0;
226
m_tablet = fpWTOpen( m_hWnd, &lc, TRUE );
228
m_tabletData = new GHOST_TabletData();
229
m_tabletData->Active = 0;
237
GHOST_WindowWin32::~GHOST_WindowWin32()
240
GHOST_WIN32_WTClose fpWTClose = ( GHOST_WIN32_WTClose ) ::GetProcAddress( m_wintab, "WTClose" );
249
if (m_customCursor) {
250
DestroyCursor(m_customCursor);
251
m_customCursor = NULL;
254
setDrawingContextType(GHOST_kDrawingContextTypeNone);
256
::ReleaseDC(m_hWnd, m_hDC);
260
::DestroyWindow(m_hWnd);
265
bool GHOST_WindowWin32::getValid() const
271
void GHOST_WindowWin32::setTitle(const STR_String& title)
273
::SetWindowText(m_hWnd, title);
277
void GHOST_WindowWin32::getTitle(STR_String& title) const
279
char buf[s_maxTitleLength];
280
::GetWindowText(m_hWnd, buf, s_maxTitleLength);
281
STR_String temp (buf);
286
void GHOST_WindowWin32::getWindowBounds(GHOST_Rect& bounds) const
289
::GetWindowRect(m_hWnd, &rect);
290
bounds.m_b = rect.bottom;
291
bounds.m_l = rect.left;
292
bounds.m_r = rect.right;
293
bounds.m_t = rect.top;
297
void GHOST_WindowWin32::getClientBounds(GHOST_Rect& bounds) const
300
::GetClientRect(m_hWnd, &rect);
301
bounds.m_b = rect.bottom;
302
bounds.m_l = rect.left;
303
bounds.m_r = rect.right;
304
bounds.m_t = rect.top;
308
GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
310
GHOST_TSuccess success;
311
GHOST_Rect cBnds, wBnds;
312
getClientBounds(cBnds);
313
if (cBnds.getWidth() != width) {
314
getWindowBounds(wBnds);
315
int cx = wBnds.getWidth() + width - cBnds.getWidth();
316
int cy = wBnds.getHeight();
317
success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
318
GHOST_kSuccess : GHOST_kFailure;
321
success = GHOST_kSuccess;
327
GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
329
GHOST_TSuccess success;
330
GHOST_Rect cBnds, wBnds;
331
getClientBounds(cBnds);
332
if (cBnds.getHeight() != height) {
333
getWindowBounds(wBnds);
334
int cx = wBnds.getWidth();
335
int cy = wBnds.getHeight() + height - cBnds.getHeight();
336
success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
337
GHOST_kSuccess : GHOST_kFailure;
340
success = GHOST_kSuccess;
346
GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
348
GHOST_TSuccess success;
349
GHOST_Rect cBnds, wBnds;
350
getClientBounds(cBnds);
351
if ((cBnds.getWidth() != width) || (cBnds.getHeight() != height)) {
352
getWindowBounds(wBnds);
353
int cx = wBnds.getWidth() + width - cBnds.getWidth();
354
int cy = wBnds.getHeight() + height - cBnds.getHeight();
355
success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
356
GHOST_kSuccess : GHOST_kFailure;
359
success = GHOST_kSuccess;
365
GHOST_TWindowState GHOST_WindowWin32::getState() const
367
GHOST_TWindowState state;
368
if (::IsIconic(m_hWnd)) {
369
state = GHOST_kWindowStateMinimized;
371
else if (::IsZoomed(m_hWnd)) {
372
state = GHOST_kWindowStateMaximized;
375
state = GHOST_kWindowStateNormal;
381
void GHOST_WindowWin32::screenToClient(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
383
POINT point = { inX, inY };
384
::ScreenToClient(m_hWnd, &point);
390
void GHOST_WindowWin32::clientToScreen(GHOST_TInt32 inX, GHOST_TInt32 inY, GHOST_TInt32& outX, GHOST_TInt32& outY) const
392
POINT point = { inX, inY };
393
::ClientToScreen(m_hWnd, &point);
399
GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
402
wp.length = sizeof(WINDOWPLACEMENT);
403
::GetWindowPlacement(m_hWnd, &wp);
405
case GHOST_kWindowStateMinimized:
406
wp.showCmd = SW_SHOWMINIMIZED;
408
case GHOST_kWindowStateMaximized:
409
ShowWindow(m_hWnd, SW_HIDE); //fe. HACK!
410
//Solves redraw problems when switching from fullscreen to normal.
412
wp.showCmd = SW_SHOWMAXIMIZED;
413
SetWindowLong(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
415
case GHOST_kWindowStateFullScreen:
416
wp.showCmd = SW_SHOWMAXIMIZED;
417
SetWindowLong(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
419
case GHOST_kWindowStateNormal:
421
wp.showCmd = SW_SHOWNORMAL;
424
return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
428
GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
430
HWND hWndInsertAfter = order == GHOST_kWindowOrderTop ? HWND_TOP : HWND_BOTTOM;
431
return ::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
435
GHOST_TSuccess GHOST_WindowWin32::swapBuffers()
437
return ::SwapBuffers(m_hDC) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
441
GHOST_TSuccess GHOST_WindowWin32::activateDrawingContext()
443
GHOST_TSuccess success;
444
if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) {
445
if (m_hDC && m_hGlRc) {
446
success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
449
success = GHOST_kFailure;
453
success = GHOST_kSuccess;
459
GHOST_TSuccess GHOST_WindowWin32::invalidate()
461
GHOST_TSuccess success;
463
success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
466
success = GHOST_kFailure;
472
GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextType type)
474
GHOST_TSuccess success;
476
case GHOST_kDrawingContextTypeOpenGL:
479
sPreferredFormat.dwFlags |= PFD_STEREO;
481
// Attempt to match device context pixel format to the preferred format
482
int iPixelFormat = EnumPixelFormats(m_hDC);
483
if (iPixelFormat == 0) {
484
success = GHOST_kFailure;
487
if (::SetPixelFormat(m_hDC, iPixelFormat, &sPreferredFormat) == FALSE) {
488
success = GHOST_kFailure;
491
// For debugging only: retrieve the pixel format chosen
492
PIXELFORMATDESCRIPTOR preferredFormat;
493
::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &preferredFormat);
494
// Create the context
495
m_hGlRc = ::wglCreateContext(m_hDC);
498
wglShareLists(s_firsthGLRc, m_hGlRc);
500
s_firsthGLRc = m_hGlRc;
503
success = ::wglMakeCurrent(m_hDC, m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
506
success = GHOST_kFailure;
511
case GHOST_kDrawingContextTypeNone:
512
success = GHOST_kSuccess;
516
success = GHOST_kFailure;
522
GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
524
GHOST_TSuccess success;
525
switch (m_drawingContextType) {
526
case GHOST_kDrawingContextTypeOpenGL:
528
success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
529
if (m_hGlRc == s_firsthGLRc) {
535
success = GHOST_kFailure;
538
case GHOST_kDrawingContextTypeNone:
539
success = GHOST_kSuccess;
542
success = GHOST_kFailure;
547
void GHOST_WindowWin32::lostMouseCapture()
549
if (m_hasMouseCaptured) {
550
m_hasMouseCaptured = false;
551
m_nPressedButtons = 0;
555
void GHOST_WindowWin32::registerMouseClickEvent(bool press)
558
if (!m_hasMouseCaptured) {
559
::SetCapture(m_hWnd);
560
m_hasMouseCaptured = true;
564
if (m_nPressedButtons) {
566
if (!m_nPressedButtons) {
568
m_hasMouseCaptured = false;
575
void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
578
while (::ShowCursor(FALSE) >= 0);
581
while (::ShowCursor(TRUE) < 0);
584
if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
585
::SetCursor( m_customCursor );
587
// Convert GHOST cursor to Windows OEM cursor
591
case GHOST_kStandardCursorDefault: id = IDC_ARROW; break;
592
case GHOST_kStandardCursorRightArrow: id = IDC_ARROW; break;
593
case GHOST_kStandardCursorLeftArrow: id = IDC_ARROW; break;
594
case GHOST_kStandardCursorInfo: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west
595
case GHOST_kStandardCursorDestroy: id = IDC_NO; break; // Slashed circle
596
case GHOST_kStandardCursorHelp: id = IDC_HELP; break; // Arrow and question mark
597
case GHOST_kStandardCursorCycle: id = IDC_NO; break; // Slashed circle
598
case GHOST_kStandardCursorSpray: id = IDC_SIZEALL; break; // Four-pointed arrow pointing north, south, east, and west
599
case GHOST_kStandardCursorWait: id = IDC_WAIT; break; // Hourglass
600
case GHOST_kStandardCursorText: id = IDC_IBEAM; break; // I-beam
601
case GHOST_kStandardCursorCrosshair: id = IDC_CROSS; break; // Crosshair
602
case GHOST_kStandardCursorUpDown: id = IDC_SIZENS; break; // Double-pointed arrow pointing north and south
603
case GHOST_kStandardCursorLeftRight: id = IDC_SIZEWE; break; // Double-pointed arrow pointing west and east
604
case GHOST_kStandardCursorTopSide: id = IDC_UPARROW; break; // Vertical arrow
605
case GHOST_kStandardCursorBottomSide: id = IDC_SIZENS; break;
606
case GHOST_kStandardCursorLeftSide: id = IDC_SIZEWE; break;
607
case GHOST_kStandardCursorTopLeftCorner: id = IDC_SIZENWSE; break;
608
case GHOST_kStandardCursorTopRightCorner: id = IDC_SIZENESW; break;
609
case GHOST_kStandardCursorBottomRightCorner: id = IDC_SIZENWSE; break;
610
case GHOST_kStandardCursorBottomLeftCorner: id = IDC_SIZENESW; break;
611
case GHOST_kStandardCursorPencil: id = IDC_ARROW; break;
617
HCURSOR hCursor = ::SetCursor(::LoadCursor(0, id));
622
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
624
if (::GetForegroundWindow() == m_hWnd) {
625
loadCursor(visible, getCursorShape());
628
return GHOST_kSuccess;
631
GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
633
if (m_customCursor) {
634
DestroyCursor(m_customCursor);
635
m_customCursor = NULL;
638
if (::GetForegroundWindow() == m_hWnd) {
639
loadCursor(getCursorVisibility(), cursorShape);
642
return GHOST_kSuccess;
644
void GHOST_WindowWin32::processWin32TabletInitEvent()
647
GHOST_WIN32_WTInfo fpWTInfo = ( GHOST_WIN32_WTInfo ) ::GetProcAddress( m_wintab, "WTInfoA" );
649
// let's see if we can initialize tablet here
650
/* check if WinTab available. */
652
AXIS Pressure, Orientation[3]; /* The maximum tablet size */
654
BOOL pressureSupport = fpWTInfo (WTI_DEVICES, DVC_NPRESSURE, &Pressure);
656
m_maxPressure = Pressure.axMax;
660
BOOL tiltSupport = fpWTInfo (WTI_DEVICES, DVC_ORIENTATION, &Orientation);
662
/* does the tablet support azimuth ([0]) and altitude ([1]) */
663
if (Orientation[0].axResolution && Orientation[1].axResolution) {
664
m_maxAzimuth = Orientation[0].axMax;
665
m_maxAltitude = Orientation[1].axMax;
667
else { /* no so dont do tilt stuff */
668
m_maxAzimuth = m_maxAltitude = 0;
672
m_tabletData->Active = 0;
677
void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
681
GHOST_WIN32_WTPacket fpWTPacket = ( GHOST_WIN32_WTPacket ) ::GetProcAddress( m_wintab, "WTPacket" );
683
if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
685
switch (pkt.pkCursor) {
686
case 0: /* first device */
687
case 3: /* second device */
688
m_tabletData->Active = 0; /* puck - not yet supported */
692
m_tabletData->Active = 1; /* stylus */
696
m_tabletData->Active = 2; /* eraser */
699
if (m_maxPressure > 0) {
700
m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
702
m_tabletData->Pressure = 1.0f;
705
if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
706
ORIENTATION ort = pkt.pkOrientation;
708
float altRad, azmRad; /* in radians */
711
from the wintab spec:
712
orAzimuth Specifies the clockwise rotation of the
713
cursor about the z axis through a full circular range.
715
orAltitude Specifies the angle with the x-y plane
716
through a signed, semicircular range. Positive values
717
specify an angle upward toward the positive z axis;
718
negative values specify an angle downward toward the negative z axis.
720
wintab.h defines .orAltitude as a UINT but documents .orAltitude
721
as positive for upward angles and negative for downward angles.
722
WACOM uses negative altitude values to show that the pen is inverted;
723
therefore we cast .orAltitude as an (int) and then use the absolute value.
726
/* convert raw fixed point data to radians */
727
altRad = (fabs((float)ort.orAltitude)/(float)m_maxAltitude) * M_PI/2.0;
728
azmRad = ((float)ort.orAzimuth/(float)m_maxAzimuth) * M_PI*2.0;
730
/* find length of the stylus' projected vector on the XY plane */
731
vecLen = cos(altRad);
733
/* from there calculate X and Y components based on azimuth */
734
m_tabletData->Xtilt = sin(azmRad) * vecLen;
735
m_tabletData->Ytilt = sin(M_PI/2.0 - azmRad) * vecLen;
738
m_tabletData->Xtilt = 0.0f;
739
m_tabletData->Ytilt = 0.0f;
747
/** Reverse the bits in a GHOST_TUns8 */
748
static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
750
ch= ((ch>>1)&0x55) | ((ch<<1)&0xAA);
751
ch= ((ch>>2)&0x33) | ((ch<<2)&0xCC);
752
ch= ((ch>>4)&0x0F) | ((ch<<4)&0xF0);
756
/** Reverse the bits in a GHOST_TUns16 */
757
static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
759
shrt= ((shrt>>1)&0x5555) | ((shrt<<1)&0xAAAA);
760
shrt= ((shrt>>2)&0x3333) | ((shrt<<2)&0xCCCC);
761
shrt= ((shrt>>4)&0x0F0F) | ((shrt<<4)&0xF0F0);
762
shrt= ((shrt>>8)&0x00FF) | ((shrt<<8)&0xFF00);
765
GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 bitmap[16][2],
766
GHOST_TUns8 mask[16][2], int hotX, int hotY)
768
return setWindowCustomCursorShape((GHOST_TUns8*)bitmap, (GHOST_TUns8*)mask,
769
16, 16, hotX, hotY, 0, 1);
772
GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(GHOST_TUns8 *bitmap,
773
GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY,
774
int fg_color, int bg_color)
776
GHOST_TUns32 andData[32];
777
GHOST_TUns32 xorData[32];
778
GHOST_TUns32 fullBitRow, fullMaskRow;
781
cols=sizeX/8; /* Num of whole bytes per row (width of bm/mask) */
784
if (m_customCursor) {
785
DestroyCursor(m_customCursor);
786
m_customCursor = NULL;
789
memset(&andData, 0xFF, sizeof(andData));
790
memset(&xorData, 0, sizeof(xorData));
792
for (y=0; y<sizeY; y++) {
795
for (x=cols-1; x>=0; x--){
798
fullBitRow |= uns8ReverseBits(bitmap[cols*y + x]);
799
fullMaskRow |= uns8ReverseBits( mask[cols*y + x]);
801
xorData[y]= fullBitRow & fullMaskRow;
802
andData[y]= ~fullMaskRow;
805
m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
806
if (!m_customCursor) {
807
return GHOST_kFailure;
810
if (::GetForegroundWindow() == m_hWnd) {
811
loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
814
return GHOST_kSuccess;
818
/* Ron Fosner's code for weighting pixel formats and forcing software.
819
See http://www.opengl.org/resources/faq/technical/weight.cpp */
821
static int WeightPixelFormat(PIXELFORMATDESCRIPTOR& pfd) {
824
/* assume desktop color depth is 32 bits per pixel */
826
/* cull unusable pixel formats */
827
/* if no formats can be found, can we determine why it was rejected? */
828
if( !(pfd.dwFlags & PFD_SUPPORT_OPENGL) ||
829
!(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
830
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
831
( pfd.cDepthBits <= 8 ) ||
832
!(pfd.iPixelType == PFD_TYPE_RGBA) )
835
weight = 1; /* it's usable */
837
/* the bigger the depth buffer the better */
838
/* give no weight to a 16-bit depth buffer, because those are crap */
839
weight += pfd.cDepthBits - 16;
841
weight += pfd.cColorBits - 8;
843
/* want swap copy capability -- it matters a lot */
844
if(pfd.dwFlags & PFD_SWAP_COPY) weight += 16;
846
/* but if it's a generic (not accelerated) view, it's really bad */
847
if(pfd.dwFlags & PFD_GENERIC_FORMAT) weight /= 10;
852
/* A modification of Ron Fosner's replacement for ChoosePixelFormat */
853
/* returns 0 on error, else returns the pixel format number to be used */
854
static int EnumPixelFormats(HDC hdc) {
856
int i, n, w, weight = 0;
857
PIXELFORMATDESCRIPTOR pfd, pfd_fallback;
859
/* we need a device context to do anything */
862
iPixelFormat = 1; /* careful! PFD numbers are 1 based, not zero based */
864
/* obtain detailed information about
865
the device context's first pixel format */
866
n = 1+::DescribePixelFormat(hdc, iPixelFormat,
867
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
869
/* choose a pixel format using the useless Windows function in case
870
we come up empty handed */
871
iPixelFormat = ::ChoosePixelFormat( hdc, &sPreferredFormat );
873
if(!iPixelFormat) return 0; /* couldn't find one to use */
875
for(i=1; i<=n; i++) { /* not the idiom, but it's right */
876
::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
877
w = WeightPixelFormat(pfd);
878
// be strict on stereo
879
if (!((sPreferredFormat.dwFlags ^ pfd.dwFlags) & PFD_STEREO)) {
887
// we could find the correct stereo setting, just find any suitable format
888
for(i=1; i<=n; i++) { /* not the idiom, but it's right */
889
::DescribePixelFormat( hdc, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd );
890
w = WeightPixelFormat(pfd);