BGE: alpha on frame buffer and precedence of MSAA over swap.
[blender.git] / intern / ghost / intern / GHOST_WindowWin32.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Maarten Gribnau.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file ghost/intern/GHOST_WindowWin32.cpp
29  *  \ingroup GHOST
30  */
31
32 #define _USE_MATH_DEFINES
33
34 #include "GHOST_WindowWin32.h"
35 #include "GHOST_SystemWin32.h"
36 #include "GHOST_DropTargetWin32.h"
37 #include "GHOST_ContextNone.h"
38 #include "utfconv.h"
39 #include "utf_winfunc.h"
40
41 #if defined(WITH_GL_EGL)
42 #  include "GHOST_ContextEGL.h"
43 #else
44 #  include "GHOST_ContextWGL.h"
45 #endif
46 #ifdef WIN32_COMPOSITING
47 #include <Dwmapi.h>
48 #endif
49
50 #include <math.h>
51 #include <string.h>
52 #include <assert.h>
53
54
55
56 const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
57 const int GHOST_WindowWin32::s_maxTitleLength = 128;
58
59
60
61
62 /* force NVidia Optimus to used dedicated graphics */
63 extern "C" {
64         __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
65 }
66
67 GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system,
68         const STR_String &title,
69         GHOST_TInt32 left,
70         GHOST_TInt32 top,
71         GHOST_TUns32 width,
72         GHOST_TUns32 height,
73         GHOST_TWindowState state,
74         GHOST_TDrawingContextType type,
75         bool wantStereoVisual,
76         bool alphaBackground,
77         GHOST_TUns16 wantNumOfAASamples,
78         GHOST_TEmbedderWindowID parentwindowhwnd,
79         bool is_debug)
80     : GHOST_Window(width, height, state,
81                    wantStereoVisual, false, wantNumOfAASamples),
82       m_inLiveResize(false),
83       m_system(system),
84       m_hDC(0),
85       m_hasMouseCaptured(false),
86       m_hasGrabMouse(false),
87       m_nPressedButtons(0),
88       m_customCursor(0),
89       m_wantAlphaBackground(alphaBackground),
90       m_wintab(NULL),
91       m_tabletData(NULL),
92       m_tablet(0),
93       m_maxPressure(0),
94       m_normal_state(GHOST_kWindowStateNormal),
95       m_parentWindowHwnd(parentwindowhwnd),
96       m_debug_context(is_debug)
97 {
98         OSVERSIONINFOEX versionInfo;
99         bool hasMinVersionForTaskbar = false;
100         
101         ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
102         
103         versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
104         
105         if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
106                 versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
107                 if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) {
108                         if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
109                             (versionInfo.dwMajorVersion >= 7))
110                         {
111                                 hasMinVersionForTaskbar = true;
112                         }
113                 }
114         }
115         else {
116                 if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) ||
117                     (versionInfo.dwMajorVersion >= 7))
118                 {
119                         hasMinVersionForTaskbar = true;
120                 }
121         }
122
123         if (state != GHOST_kWindowStateFullScreen) {
124                 RECT rect;
125                 MONITORINFO monitor;
126                 GHOST_TUns32 tw, th; 
127
128 #ifndef _MSC_VER
129                 int cxsizeframe = GetSystemMetrics(SM_CXSIZEFRAME);
130                 int cysizeframe = GetSystemMetrics(SM_CYSIZEFRAME);
131 #else
132                 // MSVC 2012+ returns bogus values from GetSystemMetrics, bug in Windows
133                 // http://connect.microsoft.com/VisualStudio/feedback/details/753224/regression-getsystemmetrics-delivers-different-values
134                 RECT cxrect = {0, 0, 0, 0};
135                 AdjustWindowRectEx(&cxrect, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_THICKFRAME | WS_DLGFRAME, FALSE, 0);
136
137                 int cxsizeframe = abs(cxrect.bottom);
138                 int cysizeframe = abs(cxrect.left);
139 #endif
140
141                 width += cxsizeframe * 2;
142                 height += cysizeframe * 2 + GetSystemMetrics(SM_CYCAPTION);
143
144                 rect.left = left;
145                 rect.right = left + width;
146                 rect.top = top;
147                 rect.bottom = top + height;
148
149                 monitor.cbSize = sizeof(monitor);
150                 monitor.dwFlags = 0;
151
152                 // take taskbar into account
153                 GetMonitorInfo(MonitorFromRect(&rect, MONITOR_DEFAULTTONEAREST), &monitor);
154
155                 th = monitor.rcWork.bottom - monitor.rcWork.top;
156                 tw = monitor.rcWork.right - monitor.rcWork.left;
157
158                 if (tw < width) {
159                         width = tw;
160                         left = monitor.rcWork.left;
161                 }
162                 else if (monitor.rcWork.right < left + (int)width)
163                         left = monitor.rcWork.right - width;
164                 else if (left < monitor.rcWork.left)
165                         left = monitor.rcWork.left;
166
167                 if (th < height) {
168                         height = th;
169                         top = monitor.rcWork.top;
170                 }
171                 else if (monitor.rcWork.bottom < top + (int)height)
172                         top = monitor.rcWork.bottom - height;
173                 else if (top < monitor.rcWork.top)
174                         top = monitor.rcWork.top;
175
176                 int wintype = WS_OVERLAPPEDWINDOW;
177                 if (m_parentWindowHwnd != 0) {
178                         wintype = WS_CHILD;
179                         GetWindowRect((HWND)m_parentWindowHwnd, &rect);
180                         left = 0;
181                         top = 0;
182                         width = rect.right - rect.left;
183                         height = rect.bottom - rect.top;
184                 }
185                 
186                 wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
187                 m_hWnd = ::CreateWindowW(
188                         s_windowClassName,          // pointer to registered class name
189                         title_16,                   // pointer to window name
190                         wintype,                    // window style
191                         left,                       // horizontal position of window
192                         top,                        // vertical position of window
193                         width,                      // window width
194                         height,                     // window height
195                         (HWND)m_parentWindowHwnd,  // handle to parent or owner window
196                         0,                          // handle to menu or child-window identifier
197                         ::GetModuleHandle(0),       // handle to application instance
198                         0);                         // pointer to window-creation data
199                 free(title_16);
200         }
201         else {
202                 wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
203                 m_hWnd = ::CreateWindowW(
204                     s_windowClassName,          // pointer to registered class name
205                     title_16,                   // pointer to window name
206                     WS_POPUP | WS_MAXIMIZE,     // window style
207                     left,                       // horizontal position of window
208                     top,                        // vertical position of window
209                     width,                      // window width
210                     height,                     // window height
211                     HWND_DESKTOP,               // handle to parent or owner window
212                     0,                          // handle to menu or child-window identifier
213                     ::GetModuleHandle(0),       // handle to application instance
214                     0);                         // pointer to window-creation data
215                 free(title_16);
216         }
217         if (m_hWnd) {
218                 // Register this window as a droptarget. Requires m_hWnd to be valid.
219                 // Note that OleInitialize(0) has to be called prior to this. Done in GHOST_SystemWin32.
220                 m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
221                 if (m_dropTarget) {
222                         ::RegisterDragDrop(m_hWnd, m_dropTarget);
223                 }
224
225                 // Store a pointer to this class in the window structure
226                 ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR) this);
227
228                 // Store the device context
229                 m_hDC = ::GetDC(m_hWnd);
230
231                 GHOST_TSuccess success = setDrawingContextType(type);
232
233                 if (success) {
234                         // Show the window
235                         int nCmdShow;
236                         switch (state) {
237                                 case GHOST_kWindowStateMaximized:
238                                         nCmdShow = SW_SHOWMAXIMIZED;
239                                         break;
240                                 case GHOST_kWindowStateMinimized:
241                                         nCmdShow = SW_SHOWMINIMIZED;
242                                         break;
243                                 case GHOST_kWindowStateNormal:
244                                 default:
245                                         nCmdShow = SW_SHOWNORMAL;
246                                         break;
247                         }
248
249                         ::ShowWindow(m_hWnd, nCmdShow);
250 #ifdef WIN32_COMPOSITING
251                         if (alphaBackground && parentwindowhwnd == 0) {
252                                 
253                                 HRESULT hr = S_OK;
254
255                                 // Create and populate the Blur Behind structure
256                                 DWM_BLURBEHIND bb = { 0 };
257
258                                 // Enable Blur Behind and apply to the entire client area
259                                 bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
260                                 bb.fEnable = true;
261                                 bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
262
263                                 // Apply Blur Behind
264                                 hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
265                                 DeleteObject(bb.hRgnBlur);
266                         }
267 #endif
268                         // Force an initial paint of the window
269                         ::UpdateWindow(m_hWnd);
270                 }
271                 else {
272                         //invalidate the window
273                         ::DestroyWindow(m_hWnd);
274                         m_hWnd = NULL;
275                 }
276         }
277
278         if (parentwindowhwnd != 0) {
279                 RAWINPUTDEVICE device = {0};
280                 device.usUsagePage  = 0x01; /* usUsagePage & usUsage for keyboard*/
281                 device.usUsage      = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
282                 device.dwFlags |= RIDEV_INPUTSINK; // makes WM_INPUT is visible for ghost when has parent window
283                 device.hwndTarget = m_hWnd;
284                 RegisterRawInputDevices(&device, 1, sizeof(device));
285         }
286
287         m_wintab = ::LoadLibrary("Wintab32.dll");
288         if (m_wintab) {
289                 GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
290                 GHOST_WIN32_WTOpen fpWTOpen = (GHOST_WIN32_WTOpen) ::GetProcAddress(m_wintab, "WTOpenA");
291
292                 // let's see if we can initialize tablet here
293                 /* check if WinTab available. */
294                 if (fpWTInfo && fpWTInfo(0, 0, NULL)) {
295                         // Now init the tablet
296                         LOGCONTEXT lc;
297                         /* The maximum tablet size, pressure and orientation (tilt) */
298                         AXIS TabletX, TabletY, Pressure, Orientation[3];
299
300                         // Open a Wintab context
301
302                         // Get default context information
303                         fpWTInfo(WTI_DEFCONTEXT, 0, &lc);
304
305                         // Open the context
306                         lc.lcPktData = PACKETDATA;
307                         lc.lcPktMode = PACKETMODE;
308                         lc.lcOptions |= CXO_MESSAGES | CXO_SYSTEM;
309
310                         /* Set the entire tablet as active */
311                         fpWTInfo(WTI_DEVICES, DVC_X, &TabletX);
312                         fpWTInfo(WTI_DEVICES, DVC_Y, &TabletY);
313
314                         /* get the max pressure, to divide into a float */
315                         BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
316                         if (pressureSupport)
317                                 m_maxPressure = Pressure.axMax;
318                         else
319                                 m_maxPressure = 0;
320
321                         /* get the max tilt axes, to divide into floats */
322                         BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
323                         if (tiltSupport) {
324                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
325                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
326                                         /* all this assumes the minimum is 0 */
327                                         m_maxAzimuth = Orientation[0].axMax;
328                                         m_maxAltitude = Orientation[1].axMax;
329                                 }
330                                 else {  /* no so dont do tilt stuff */
331                                         m_maxAzimuth = m_maxAltitude = 0;
332                                 }
333                         }
334
335                         if (fpWTOpen) {
336                                 m_tablet = fpWTOpen(m_hWnd, &lc, TRUE);
337                                 if (m_tablet) {
338                                         m_tabletData = new GHOST_TabletData();
339                                         m_tabletData->Active = GHOST_kTabletModeNone;
340                                 }
341                         }
342                 }
343         }
344
345         if (hasMinVersionForTaskbar)
346                 CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar);
347         else
348                 m_Bar = NULL;
349 }
350
351
352 GHOST_WindowWin32::~GHOST_WindowWin32()
353 {
354         if (m_Bar) {
355                 m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
356                 m_Bar->Release();
357         }
358
359         if (m_wintab) {
360                 GHOST_WIN32_WTClose fpWTClose = (GHOST_WIN32_WTClose) ::GetProcAddress(m_wintab, "WTClose");
361                 if (fpWTClose) {
362                         if (m_tablet)
363                                 fpWTClose(m_tablet);
364                         delete m_tabletData;
365                         m_tabletData = NULL;
366                 }
367         }
368
369         if (m_customCursor) {
370                 DestroyCursor(m_customCursor);
371                 m_customCursor = NULL;
372         }
373
374         if (m_hWnd != NULL && m_hDC != NULL && releaseNativeHandles()) {
375                 ::ReleaseDC(m_hWnd, m_hDC);
376         }
377
378         if (m_hWnd) {
379                 if (m_dropTarget) {
380                         // Disable DragDrop
381                         RevokeDragDrop(m_hWnd);
382                         // Release our reference of the DropTarget and it will delete itself eventually.
383                         m_dropTarget->Release();
384                 }
385
386                 ::DestroyWindow(m_hWnd);
387                 m_hWnd = 0;
388         }
389 }
390
391 bool GHOST_WindowWin32::getValid() const
392 {
393         return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0;
394 }
395
396 HWND GHOST_WindowWin32::getHWND() const
397 {
398         return m_hWnd;
399 }
400
401 void GHOST_WindowWin32::setTitle(const STR_String &title)
402 {
403         wchar_t *title_16 = alloc_utf16_from_8((char *)(const char *)title, 0);
404         ::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
405         free(title_16);
406 }
407
408
409 void GHOST_WindowWin32::getTitle(STR_String &title) const
410 {
411         char buf[s_maxTitleLength]; /*CHANGE + never used yet*/
412         ::GetWindowText(m_hWnd, buf, s_maxTitleLength);
413         STR_String temp(buf);
414         title = buf;
415 }
416
417
418 void GHOST_WindowWin32::getWindowBounds(GHOST_Rect &bounds) const
419 {
420         RECT rect;
421         ::GetWindowRect(m_hWnd, &rect);
422         bounds.m_b = rect.bottom;
423         bounds.m_l = rect.left;
424         bounds.m_r = rect.right;
425         bounds.m_t = rect.top;
426 }
427
428
429 void GHOST_WindowWin32::getClientBounds(GHOST_Rect &bounds) const
430 {
431         RECT rect;
432         POINT coord;
433         ::GetClientRect(m_hWnd, &rect);
434
435         coord.x = rect.left;
436         coord.y = rect.top;
437         ::ClientToScreen(m_hWnd, &coord);
438
439         bounds.m_l = coord.x;
440         bounds.m_t = coord.y;
441
442         coord.x = rect.right;
443         coord.y = rect.bottom;
444         ::ClientToScreen(m_hWnd, &coord);
445
446         bounds.m_r = coord.x;
447         bounds.m_b = coord.y;
448 }
449
450
451 GHOST_TSuccess GHOST_WindowWin32::setClientWidth(GHOST_TUns32 width)
452 {
453         GHOST_TSuccess success;
454         GHOST_Rect cBnds, wBnds;
455         getClientBounds(cBnds);
456         if (cBnds.getWidth() != (GHOST_TInt32)width) {
457                 getWindowBounds(wBnds);
458                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
459                 int cy = wBnds.getHeight();
460                 success =  ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
461                           GHOST_kSuccess : GHOST_kFailure;
462         }
463         else {
464                 success = GHOST_kSuccess;
465         }
466         return success;
467 }
468
469
470 GHOST_TSuccess GHOST_WindowWin32::setClientHeight(GHOST_TUns32 height)
471 {
472         GHOST_TSuccess success;
473         GHOST_Rect cBnds, wBnds;
474         getClientBounds(cBnds);
475         if (cBnds.getHeight() != (GHOST_TInt32)height) {
476                 getWindowBounds(wBnds);
477                 int cx = wBnds.getWidth();
478                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
479                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
480                           GHOST_kSuccess : GHOST_kFailure;
481         }
482         else {
483                 success = GHOST_kSuccess;
484         }
485         return success;
486 }
487
488
489 GHOST_TSuccess GHOST_WindowWin32::setClientSize(GHOST_TUns32 width, GHOST_TUns32 height)
490 {
491         GHOST_TSuccess success;
492         GHOST_Rect cBnds, wBnds;
493         getClientBounds(cBnds);
494         if ((cBnds.getWidth() != (GHOST_TInt32)width) || (cBnds.getHeight() != (GHOST_TInt32)height)) {
495                 getWindowBounds(wBnds);
496                 int cx = wBnds.getWidth() + width - cBnds.getWidth();
497                 int cy = wBnds.getHeight() + height - cBnds.getHeight();
498                 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
499                           GHOST_kSuccess : GHOST_kFailure;
500         }
501         else {
502                 success = GHOST_kSuccess;
503         }
504         return success;
505 }
506
507
508 GHOST_TWindowState GHOST_WindowWin32::getState() const
509 {
510         GHOST_TWindowState state;
511
512         // XXX 27.04.2011
513         // we need to find a way to combine parented windows + resizing if we simply set the
514         // state as GHOST_kWindowStateEmbedded we will need to check for them somewhere else.
515         // It's also strange that in Windows is the only platform we need to make this separation.
516         if (m_parentWindowHwnd != 0) {
517                 state = GHOST_kWindowStateEmbedded;
518                 return state;
519         }
520
521         if (::IsIconic(m_hWnd)) {
522                 state = GHOST_kWindowStateMinimized;
523         }
524         else if (::IsZoomed(m_hWnd)) {
525                 LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
526                 if ((result & (WS_POPUP | WS_MAXIMIZE)) != (WS_POPUP | WS_MAXIMIZE))
527                         state = GHOST_kWindowStateMaximized;
528                 else
529                         state = GHOST_kWindowStateFullScreen;
530         }
531         else {
532                 state = GHOST_kWindowStateNormal;
533         }
534         return state;
535 }
536
537
538 void GHOST_WindowWin32::screenToClient(
539         GHOST_TInt32 inX, GHOST_TInt32 inY,
540         GHOST_TInt32 &outX, GHOST_TInt32 &outY) const
541 {
542         POINT point = {inX, inY};
543         ::ScreenToClient(m_hWnd, &point);
544         outX = point.x;
545         outY = point.y;
546 }
547
548
549 void GHOST_WindowWin32::clientToScreen(
550         GHOST_TInt32 inX, GHOST_TInt32 inY,
551         GHOST_TInt32 &outX, GHOST_TInt32 &outY) const
552 {
553         POINT point = {inX, inY};
554         ::ClientToScreen(m_hWnd, &point);
555         outX = point.x;
556         outY = point.y;
557 }
558
559
560 GHOST_TSuccess GHOST_WindowWin32::setState(GHOST_TWindowState state)
561 {
562         GHOST_TWindowState curstate = getState();
563         WINDOWPLACEMENT wp;
564         wp.length = sizeof(WINDOWPLACEMENT);
565         ::GetWindowPlacement(m_hWnd, &wp);
566
567         if (state == GHOST_kWindowStateNormal)
568                 state = m_normal_state;
569
570         switch (state) {
571                 case GHOST_kWindowStateMinimized:
572                         wp.showCmd = SW_SHOWMINIMIZED;
573                         break;
574                 case GHOST_kWindowStateMaximized:
575                         wp.showCmd = SW_SHOWMAXIMIZED;
576                         ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
577                         break;
578                 case GHOST_kWindowStateFullScreen:
579                         if (curstate != state && curstate != GHOST_kWindowStateMinimized)
580                                 m_normal_state = curstate;
581                         wp.showCmd = SW_SHOWMAXIMIZED;
582                         wp.ptMaxPosition.x = 0;
583                         wp.ptMaxPosition.y = 0;
584                         ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_POPUP | WS_MAXIMIZE);
585                         break;
586                 case GHOST_kWindowStateEmbedded:
587                         ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_CHILD);
588                         break;
589                 case GHOST_kWindowStateNormal:
590                 default:
591                         wp.showCmd = SW_SHOWNORMAL;
592                         ::SetWindowLongPtr(m_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
593                         break;
594         }
595         /* Clears window cache for SetWindowLongPtr */
596         ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
597
598         return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
599 }
600
601
602 GHOST_TSuccess GHOST_WindowWin32::setOrder(GHOST_TWindowOrder order)
603 {
604         HWND hWndInsertAfter, hWndToRaise;
605
606         if (order == GHOST_kWindowOrderBottom) {
607                 hWndInsertAfter = HWND_BOTTOM;
608                 hWndToRaise = ::GetWindow(m_hWnd, GW_HWNDNEXT); /* the window to raise */
609         }
610         else {
611                 hWndInsertAfter = HWND_TOP;
612                 hWndToRaise = NULL;
613         }
614
615         if (::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
616                 return GHOST_kFailure;
617         }
618
619         if (hWndToRaise && ::SetWindowPos(hWndToRaise, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
620                 return GHOST_kFailure;
621         }
622         return GHOST_kSuccess;
623 }
624
625
626 GHOST_TSuccess GHOST_WindowWin32::invalidate()
627 {
628         GHOST_TSuccess success;
629         if (m_hWnd) {
630                 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
631         }
632         else {
633                 success = GHOST_kFailure;
634         }
635         return success;
636 }
637
638
639 GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type)
640 {
641         if (type == GHOST_kDrawingContextTypeOpenGL) {
642 #if !defined(WITH_GL_EGL)
643
644 #if defined(WITH_GL_PROFILE_CORE)
645                 GHOST_Context *context = new GHOST_ContextWGL(
646                         m_wantStereoVisual,
647                         m_wantAlphaBackground,
648                         m_wantNumOfAASamples,
649                         m_hWnd,
650                         m_hDC,
651                         WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
652                         3, 2,
653                         GHOST_OPENGL_WGL_CONTEXT_FLAGS,
654                         GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
655 #elif defined(WITH_GL_PROFILE_ES20)
656                 GHOST_Context *context = new GHOST_ContextWGL(
657                         m_wantStereoVisual,
658                         m_wantAlphaBackground,
659                         m_wantNumOfAASamples,
660                         m_hWnd,
661                         m_hDC,
662                         WGL_CONTEXT_ES2_PROFILE_BIT_EXT,
663                         2, 0,
664                         GHOST_OPENGL_WGL_CONTEXT_FLAGS,
665                         GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
666 #elif defined(WITH_GL_PROFILE_COMPAT)
667                 GHOST_Context *context = new GHOST_ContextWGL(
668                         m_wantStereoVisual,
669                         m_wantAlphaBackground,
670                         m_wantNumOfAASamples,
671                         m_hWnd,
672                         m_hDC,
673 #if 1
674                         0, // profile bit
675                         2, 1, // GL version requested
676 #else
677                         // switch to this for Blender 2.8 development
678                         WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
679                         3, 2,
680 #endif
681                         GHOST_OPENGL_WGL_CONTEXT_FLAGS,
682                         GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY);
683 #else
684 #  error
685 #endif
686
687 #else
688
689 #if defined(WITH_GL_PROFILE_CORE)
690                 GHOST_Context *context = new GHOST_ContextEGL(
691                         m_wantStereoVisual,
692                         m_wantNumOfAASamples,
693                         m_hWnd,
694                         m_hDC,
695                         EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
696                         3, 2,
697                         GHOST_OPENGL_EGL_CONTEXT_FLAGS,
698                         GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
699                         EGL_OPENGL_API);
700 #elif defined(WITH_GL_PROFILE_ES20)
701                 GHOST_Context *context = new GHOST_ContextEGL(
702                         m_wantStereoVisual,
703                         m_wantNumOfAASamples,
704                         m_hWnd,
705                         m_hDC,
706                         0, // profile bit
707                         2, 0,
708                         GHOST_OPENGL_EGL_CONTEXT_FLAGS,
709                         GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
710                         EGL_OPENGL_ES_API);
711 #elif defined(WITH_GL_PROFILE_COMPAT)
712                 GHOST_Context *context = new GHOST_ContextEGL(
713                         m_wantStereoVisual,
714                         m_wantNumOfAASamples,
715                         m_hWnd,
716                         m_hDC,
717 #if 1
718                         0, // profile bit
719                         2, 1, // GL version requested
720 #else
721                         // switch to this for Blender 2.8 development
722                         EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
723                         3, 2,
724 #endif
725                         GHOST_OPENGL_EGL_CONTEXT_FLAGS,
726                         GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY,
727                         EGL_OPENGL_API);
728 #else
729 #  error
730 #endif
731
732 #endif
733                 if (context->initializeDrawingContext())
734                         return context;
735                 else
736                         delete context;
737         }
738
739         return NULL;
740 }
741
742 void GHOST_WindowWin32::lostMouseCapture()
743 {
744         if (m_hasMouseCaptured) {
745                 m_hasGrabMouse = false;
746                 m_nPressedButtons = 0;
747                 m_hasMouseCaptured = false;
748         }
749 }
750
751 void GHOST_WindowWin32::registerMouseClickEvent(int press)
752 {
753
754         switch (press) {
755                 case 0: m_nPressedButtons++;    break;
756                 case 1: if (m_nPressedButtons) m_nPressedButtons--; break;
757                 case 2: m_hasGrabMouse = true;    break;
758                 case 3: m_hasGrabMouse = false;   break;
759         }
760
761         if (!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured) {
762                 ::ReleaseCapture();
763                 m_hasMouseCaptured = false;
764         }
765         else if ((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured) {
766                 ::SetCapture(m_hWnd);
767                 m_hasMouseCaptured = true;
768
769         }
770 }
771
772
773 void GHOST_WindowWin32::loadCursor(bool visible, GHOST_TStandardCursor cursor) const
774 {
775         if (!visible) {
776                 while (::ShowCursor(FALSE) >= 0) ;
777         }
778         else {
779                 while (::ShowCursor(TRUE) < 0) ;
780         }
781
782         if (cursor == GHOST_kStandardCursorCustom && m_customCursor) {
783                 ::SetCursor(m_customCursor);
784         }
785         else {
786                 // Convert GHOST cursor to Windows OEM cursor
787                 bool success = true;
788                 LPCSTR id;
789                 switch (cursor) {
790                         case GHOST_kStandardCursorDefault:              id = IDC_ARROW;     break;
791                         case GHOST_kStandardCursorRightArrow:           id = IDC_ARROW;     break;
792                         case GHOST_kStandardCursorLeftArrow:            id = IDC_ARROW;     break;
793                         case GHOST_kStandardCursorInfo:                 id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
794                         case GHOST_kStandardCursorDestroy:              id = IDC_NO;        break;  // Slashed circle
795                         case GHOST_kStandardCursorHelp:                 id = IDC_HELP;      break;  // Arrow and question mark
796                         case GHOST_kStandardCursorCycle:                id = IDC_NO;        break;  // Slashed circle
797                         case GHOST_kStandardCursorSpray:                id = IDC_SIZEALL;   break;  // Four-pointed arrow pointing north, south, east, and west
798                         case GHOST_kStandardCursorWait:                 id = IDC_WAIT;      break;  // Hourglass
799                         case GHOST_kStandardCursorText:                 id = IDC_IBEAM;     break;  // I-beam
800                         case GHOST_kStandardCursorCrosshair:            id = IDC_CROSS;     break;  // Crosshair
801                         case GHOST_kStandardCursorUpDown:               id = IDC_SIZENS;    break;  // Double-pointed arrow pointing north and south
802                         case GHOST_kStandardCursorLeftRight:            id = IDC_SIZEWE;    break;  // Double-pointed arrow pointing west and east
803                         case GHOST_kStandardCursorTopSide:              id = IDC_UPARROW;   break;  // Vertical arrow
804                         case GHOST_kStandardCursorBottomSide:           id = IDC_SIZENS;    break;
805                         case GHOST_kStandardCursorLeftSide:             id = IDC_SIZEWE;    break;
806                         case GHOST_kStandardCursorTopLeftCorner:        id = IDC_SIZENWSE;  break;
807                         case GHOST_kStandardCursorTopRightCorner:       id = IDC_SIZENESW;  break;
808                         case GHOST_kStandardCursorBottomRightCorner:    id = IDC_SIZENWSE;  break;
809                         case GHOST_kStandardCursorBottomLeftCorner:     id = IDC_SIZENESW;  break;
810                         case GHOST_kStandardCursorPencil:               id = IDC_ARROW;     break;
811                         case GHOST_kStandardCursorCopy:                 id = IDC_ARROW;     break;
812                         default:
813                                 success = false;
814                 }
815
816                 if (success) {
817                         ::SetCursor(::LoadCursor(0, id));
818                 }
819         }
820 }
821
822 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
823 {
824         if (::GetForegroundWindow() == m_hWnd) {
825                 loadCursor(visible, getCursorShape());
826         }
827
828         return GHOST_kSuccess;
829 }
830
831 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
832 {
833         if (mode != GHOST_kGrabDisable) {
834                 if (mode != GHOST_kGrabNormal) {
835                         m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
836                         setCursorGrabAccum(0, 0);
837
838                         if (mode == GHOST_kGrabHide)
839                                 setWindowCursorVisibility(false);
840                 }
841                 registerMouseClickEvent(2);
842         }
843         else {
844                 if (m_cursorGrab == GHOST_kGrabHide) {
845                         m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
846                         setWindowCursorVisibility(true);
847                 }
848                 if (m_cursorGrab != GHOST_kGrabNormal) {
849                         /* use to generate a mouse move event, otherwise the last event
850                          * blender gets can be outside the screen causing menus not to show
851                          * properly unless the user moves the mouse */
852                         GHOST_TInt32 pos[2];
853                         m_system->getCursorPosition(pos[0], pos[1]);
854                         m_system->setCursorPosition(pos[0], pos[1]);
855                 }
856
857                 /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */
858                 setCursorGrabAccum(0, 0);
859                 m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
860                 registerMouseClickEvent(3);
861         }
862         
863         return GHOST_kSuccess;
864 }
865
866 GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
867 {
868         if (m_customCursor) {
869                 DestroyCursor(m_customCursor);
870                 m_customCursor = NULL;
871         }
872
873         if (::GetForegroundWindow() == m_hWnd) {
874                 loadCursor(getCursorVisibility(), cursorShape);
875         }
876
877         return GHOST_kSuccess;
878 }
879
880 void GHOST_WindowWin32::processWin32TabletInitEvent()
881 {
882         if (m_wintab && m_tabletData) {
883                 GHOST_WIN32_WTInfo fpWTInfo = (GHOST_WIN32_WTInfo) ::GetProcAddress(m_wintab, "WTInfoA");
884
885                 // let's see if we can initialize tablet here
886                 /* check if WinTab available. */
887                 if (fpWTInfo) {
888                         AXIS Pressure, Orientation[3]; /* The maximum tablet size */
889
890                         BOOL pressureSupport = fpWTInfo(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
891                         if (pressureSupport)
892                                 m_maxPressure = Pressure.axMax;
893                         else
894                                 m_maxPressure = 0;
895
896                         BOOL tiltSupport = fpWTInfo(WTI_DEVICES, DVC_ORIENTATION, &Orientation);
897                         if (tiltSupport) {
898                                 /* does the tablet support azimuth ([0]) and altitude ([1]) */
899                                 if (Orientation[0].axResolution && Orientation[1].axResolution) {
900                                         m_maxAzimuth = Orientation[0].axMax;
901                                         m_maxAltitude = Orientation[1].axMax;
902                                 }
903                                 else {  /* no so dont do tilt stuff */
904                                         m_maxAzimuth = m_maxAltitude = 0;
905                                 }
906                         }
907
908                         m_tabletData->Active = GHOST_kTabletModeNone;
909                 }
910         }
911 }
912
913 void GHOST_WindowWin32::processWin32TabletEvent(WPARAM wParam, LPARAM lParam)
914 {
915         PACKET pkt;
916         if (m_wintab) {
917                 GHOST_WIN32_WTPacket fpWTPacket = (GHOST_WIN32_WTPacket) ::GetProcAddress(m_wintab, "WTPacket");
918                 if (fpWTPacket) {
919                         if (fpWTPacket((HCTX)lParam, wParam, &pkt)) {
920                                 if (m_tabletData) {
921                                         switch (pkt.pkCursor) {
922                                                 case 0: /* first device */
923                                                 case 3: /* second device */
924                                                         m_tabletData->Active = GHOST_kTabletModeNone; /* puck - not yet supported */
925                                                         break;
926                                                 case 1:
927                                                 case 4:
928                                                 case 7:
929                                                         m_tabletData->Active = GHOST_kTabletModeStylus; /* stylus */
930                                                         break;
931                                                 case 2:
932                                                 case 5:
933                                                 case 8:
934                                                         m_tabletData->Active = GHOST_kTabletModeEraser; /* eraser */
935                                                         break;
936                                         }
937                                         if (m_maxPressure > 0) {
938                                                 m_tabletData->Pressure = (float)pkt.pkNormalPressure / (float)m_maxPressure;
939                                         }
940                                         else {
941                                                 m_tabletData->Pressure = 1.0f;
942                                         }
943
944                                         if ((m_maxAzimuth > 0) && (m_maxAltitude > 0)) {
945                                                 ORIENTATION ort = pkt.pkOrientation;
946                                                 float vecLen;
947                                                 float altRad, azmRad;   /* in radians */
948
949                                                 /*
950                                                  * from the wintab spec:
951                                                  * orAzimuth    Specifies the clockwise rotation of the
952                                                  * cursor about the z axis through a full circular range.
953                                                  *
954                                                  * orAltitude   Specifies the angle with the x-y plane
955                                                  * through a signed, semicircular range.  Positive values
956                                                  * specify an angle upward toward the positive z axis;
957                                                  * negative values specify an angle downward toward the negative z axis.
958                                                  *
959                                                  * wintab.h defines .orAltitude as a UINT but documents .orAltitude
960                                                  * as positive for upward angles and negative for downward angles.
961                                                  * WACOM uses negative altitude values to show that the pen is inverted;
962                                                  * therefore we cast .orAltitude as an (int) and then use the absolute value.
963                                                  */
964
965                                                 /* convert raw fixed point data to radians */
966                                                 altRad = (float)((fabs((float)ort.orAltitude) / (float)m_maxAltitude) * M_PI / 2.0);
967                                                 azmRad = (float)(((float)ort.orAzimuth / (float)m_maxAzimuth) * M_PI * 2.0);
968
969                                                 /* find length of the stylus' projected vector on the XY plane */
970                                                 vecLen = cos(altRad);
971
972                                                 /* from there calculate X and Y components based on azimuth */
973                                                 m_tabletData->Xtilt = sin(azmRad) * vecLen;
974                                                 m_tabletData->Ytilt = (float)(sin(M_PI / 2.0 - azmRad) * vecLen);
975
976                                         }
977                                         else {
978                                                 m_tabletData->Xtilt = 0.0f;
979                                                 m_tabletData->Ytilt = 0.0f;
980                                         }
981                                 }
982                         }
983                 }
984         }
985 }
986
987 void GHOST_WindowWin32::bringTabletContextToFront()
988 {
989         if (m_wintab) {
990                 GHOST_WIN32_WTOverlap fpWTOverlap = (GHOST_WIN32_WTOverlap) ::GetProcAddress(m_wintab, "WTOverlap");
991                 if (fpWTOverlap) {
992                         fpWTOverlap(m_tablet, TRUE);
993                 }
994         }
995 }
996
997 /** Reverse the bits in a GHOST_TUns8 */
998 static GHOST_TUns8 uns8ReverseBits(GHOST_TUns8 ch)
999 {
1000         ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1001         ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1002         ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1003         return ch;
1004 }
1005
1006 #if 0  /* UNUSED */
1007 /** Reverse the bits in a GHOST_TUns16 */
1008 static GHOST_TUns16 uns16ReverseBits(GHOST_TUns16 shrt)
1009 {
1010         shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1011         shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1012         shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1013         shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1014         return shrt;
1015 }
1016 #endif
1017 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(
1018         GHOST_TUns8 bitmap[16][2],
1019         GHOST_TUns8 mask[16][2],
1020         int hotX, int hotY)
1021 {
1022         return setWindowCustomCursorShape((GHOST_TUns8 *)bitmap, (GHOST_TUns8 *)mask,
1023                                           16, 16, hotX, hotY, 0, 1);
1024 }
1025
1026 GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(
1027         GHOST_TUns8 *bitmap,
1028         GHOST_TUns8 *mask, int sizeX, int sizeY, int hotX, int hotY,
1029         int fg_color, int bg_color)
1030 {
1031         GHOST_TUns32 andData[32];
1032         GHOST_TUns32 xorData[32];
1033         GHOST_TUns32 fullBitRow, fullMaskRow;
1034         int x, y, cols;
1035
1036         cols = sizeX / 8; /* Num of whole bytes per row (width of bm/mask) */
1037         if (sizeX % 8) cols++;
1038
1039         if (m_customCursor) {
1040                 DestroyCursor(m_customCursor);
1041                 m_customCursor = NULL;
1042         }
1043
1044         memset(&andData, 0xFF, sizeof(andData));
1045         memset(&xorData, 0, sizeof(xorData));
1046
1047         for (y = 0; y < sizeY; y++) {
1048                 fullBitRow = 0;
1049                 fullMaskRow = 0;
1050                 for (x = cols - 1; x >= 0; x--) {
1051                         fullBitRow <<= 8;
1052                         fullMaskRow <<= 8;
1053                         fullBitRow  |= uns8ReverseBits(bitmap[cols * y + x]);
1054                         fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1055                 }
1056                 xorData[y] = fullBitRow & fullMaskRow;
1057                 andData[y] = ~fullMaskRow;
1058         }
1059
1060         m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1061         if (!m_customCursor) {
1062                 return GHOST_kFailure;
1063         }
1064
1065         if (::GetForegroundWindow() == m_hWnd) {
1066                 loadCursor(getCursorVisibility(), GHOST_kStandardCursorCustom);
1067         }
1068
1069         return GHOST_kSuccess;
1070 }
1071
1072
1073 GHOST_TSuccess GHOST_WindowWin32::setProgressBar(float progress)
1074 {       
1075         /*SetProgressValue sets state to TBPF_NORMAL automaticly*/
1076         if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000))
1077                 return GHOST_kSuccess;
1078
1079         return GHOST_kFailure;
1080 }
1081
1082 GHOST_TSuccess GHOST_WindowWin32::endProgressBar()
1083 {
1084         if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS))
1085                 return GHOST_kSuccess;
1086
1087         return GHOST_kFailure;
1088 }
1089
1090
1091 #ifdef WITH_INPUT_IME
1092 void GHOST_WindowWin32::beginIME(GHOST_TInt32 x, GHOST_TInt32 y, GHOST_TInt32 w, GHOST_TInt32 h, int completed)
1093 {
1094         m_imeImput.BeginIME(m_hWnd, GHOST_Rect(x, y - h, x, y), (bool)completed);
1095 }
1096
1097
1098 void GHOST_WindowWin32::endIME()
1099 {
1100         m_imeImput.EndIME(m_hWnd);
1101 }
1102 #endif /* WITH_INPUT_IME */