Blender V4.3
GHOST_WindowWin32.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10#include "GHOST_ContextD3D.hh"
11#include "GHOST_ContextNone.hh"
13#include "GHOST_SystemWin32.hh"
15#include "utf_winfunc.hh"
16#include "utfconv.hh"
17
18#ifdef WITH_OPENGL_BACKEND
19# include "GHOST_ContextWGL.hh"
20#endif
21#ifdef WITH_VULKAN_BACKEND
22# include "GHOST_ContextVK.hh"
23#endif
24
25#ifdef WIN32
26# include "BLI_path_utils.hh"
27#endif
28
29#include <Dwmapi.h>
30
31#include <assert.h>
32#include <math.h>
33#include <propkey.h>
34#include <propvarutil.h>
35#include <shellapi.h>
36#include <shellscalingapi.h>
37#include <string.h>
38#include <windowsx.h>
39
40#ifndef GET_POINTERID_WPARAM
41# define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam))
42#endif /* GET_POINTERID_WPARAM */
43
44const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
45const int GHOST_WindowWin32::s_maxTitleLength = 128;
46
47/* force NVidia OPTIMUS to used dedicated graphics */
48extern "C" {
49__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
50}
51
53 const char *title,
54 int32_t left,
55 int32_t top,
56 uint32_t width,
57 uint32_t height,
60 bool wantStereoVisual,
61 bool alphaBackground,
62 GHOST_WindowWin32 *parentwindow,
63 bool is_debug,
64 bool dialog,
65 const GHOST_GPUDevice &preferred_device)
66 : GHOST_Window(width, height, state, wantStereoVisual, false),
67 m_mousePresent(false),
68 m_inLiveResize(false),
69 m_system(system),
70 m_dropTarget(nullptr),
71 m_hWnd(0),
72 m_hDC(0),
73 m_isDialog(dialog),
74 m_preferred_device(preferred_device),
75 m_hasMouseCaptured(false),
76 m_hasGrabMouse(false),
77 m_nPressedButtons(0),
78 m_customCursor(0),
79 m_wantAlphaBackground(alphaBackground),
80 m_Bar(nullptr),
81 m_wintab(nullptr),
82 m_lastPointerTabletData(GHOST_TABLET_DATA_NONE),
83 m_normal_state(GHOST_kWindowStateNormal),
84 m_user32(::LoadLibrary("user32.dll")),
85 m_parentWindowHwnd(parentwindow ? parentwindow->m_hWnd : HWND_DESKTOP),
86 m_directManipulationHelper(nullptr),
87 m_debug_context(is_debug)
88{
89 DWORD style = parentwindow ?
90 WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX :
91 WS_OVERLAPPEDWINDOW;
92
94 style |= WS_MAXIMIZE;
95 }
96
97 /* Forces owned windows onto taskbar and allows minimization. */
98 DWORD extended_style = parentwindow ? WS_EX_APPWINDOW : 0;
99
100 if (dialog) {
101 /* When we are ready to make windows of this type:
102 * style = WS_POPUPWINDOW | WS_CAPTION
103 * extended_style = WS_EX_DLGMODALFRAME | WS_EX_TOPMOST
104 */
105 }
106
107 RECT win_rect = {left, top, long(left + width), long(top + height)};
108 adjustWindowRectForClosestMonitor(&win_rect, style, extended_style);
109
110 wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
111 m_hWnd = ::CreateWindowExW(extended_style, /* window extended style */
112 s_windowClassName, /* pointer to registered class name */
113 title_16, /* pointer to window name */
114 style, /* window style */
115 win_rect.left, /* horizontal position of window */
116 win_rect.top, /* vertical position of window */
117 win_rect.right - win_rect.left, /* window width */
118 win_rect.bottom - win_rect.top, /* window height */
119 m_parentWindowHwnd, /* handle to parent or owner window */
120 0, /* handle to menu or child-window identifier */
121 ::GetModuleHandle(0), /* handle to application instance */
122 0); /* pointer to window-creation data */
123 free(title_16);
124
125 if (m_hWnd == nullptr) {
126 return;
127 }
128
129 registerWindowAppUserModelProperties();
130
131 /* Store the device context. */
132 m_hDC = ::GetDC(m_hWnd);
133
134 if (!setDrawingContextType(type)) {
135 const char *title = "Blender - Unsupported Graphics Card Configuration";
136 const char *text = "";
137#if defined(WIN32)
138 if (strncmp(BLI_getenv("PROCESSOR_IDENTIFIER"), "ARM", 3) == 0 &&
139 strstr(BLI_getenv("PROCESSOR_IDENTIFIER"), "Qualcomm") != NULL)
140 {
141 text =
142 "A driver with support for OpenGL 4.3 or higher is required.\n\n"
143 "Qualcomm devices require the \"OpenCL™, OpenGL®, and Vulkan® Compatibility Pack\" "
144 "from the Microsoft Store.\n\n"
145 "Devices using processors older than a Qualcomm Snapdragon 8cx Gen3 are incompatible, "
146 "but may be able to run an emulated x64 copy of Blender, such as a 3.x LTS release.";
147 }
148 else
149#endif
150 {
151 text =
152 "A graphics card and driver with support for OpenGL 4.3 or higher is "
153 "required.\n\nInstalling the latest driver for your graphics card might resolve the "
154 "issue.";
155 if (GetSystemMetrics(SM_CMONITORS) > 1) {
156 text =
157 "A graphics card and driver with support for OpenGL 4.3 or higher is "
158 "required.\n\nPlugging all monitors into your primary graphics card might resolve "
159 "this issue. Installing the latest driver for your graphics card could also help.";
160 }
161 }
162 MessageBox(m_hWnd, text, title, MB_OK | MB_ICONERROR);
163 ::ReleaseDC(m_hWnd, m_hDC);
164 ::DestroyWindow(m_hWnd);
165 m_hWnd = nullptr;
166 if (!parentwindow) {
167 exit(0);
168 }
169 return;
170 }
171
172 RegisterTouchWindow(m_hWnd, 0);
173
174 /* Register as drop-target. #OleInitialize(0) required first, done in GHOST_SystemWin32. */
175 m_dropTarget = new GHOST_DropTargetWin32(this, m_system);
176 ::RegisterDragDrop(m_hWnd, m_dropTarget);
177
178 /* Store a pointer to this class in the window structure. */
179 ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, (LONG_PTR)this);
180
181 if (!m_system->m_windowFocus) {
182 /* If we don't want focus then lower to bottom. */
183 ::SetWindowPos(m_hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
184 }
185
186 if (parentwindow) {
187 /* Release any parent capture to allow immediate interaction (#90110). */
188 ::ReleaseCapture();
189 parentwindow->lostMouseCapture();
190 }
191
192 /* Show the window. */
193 int nCmdShow;
194 switch (state) {
196 nCmdShow = SW_SHOWMAXIMIZED;
197 break;
199 nCmdShow = (m_system->m_windowFocus) ? SW_SHOWMINIMIZED : SW_SHOWMINNOACTIVE;
200 break;
202 default:
203 nCmdShow = (m_system->m_windowFocus) ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
204 break;
205 }
206
207 ThemeRefresh();
208
209 ::ShowWindow(m_hWnd, nCmdShow);
210
211#ifdef WIN32_COMPOSITING
212 if (alphaBackground && parentwindowhwnd == 0) {
213
214 HRESULT hr = S_OK;
215
216 /* Create and populate the Blur Behind structure. */
217 DWM_BLURBEHIND bb = {0};
218
219 /* Enable Blur Behind and apply to the entire client area. */
220 bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
221 bb.fEnable = true;
222 bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
223
224 /* Apply Blur Behind. */
225 hr = DwmEnableBlurBehindWindow(m_hWnd, &bb);
226 DeleteObject(bb.hRgnBlur);
227 }
228#endif
229
230 /* Initialize WINTAB. */
231 if (system->getTabletAPI() != GHOST_kTabletWinPointer) {
233 }
234
235 /* Allow the showing of a progress bar on the taskbar. */
236 CoCreateInstance(
237 CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
238
239 /* Initialize Direct Manipulation. */
240 m_directManipulationHelper = GHOST_DirectManipulationHelper::create(m_hWnd, getDPIHint());
241}
242
244{
245 if (!m_directManipulationHelper) {
246 return;
247 }
248
249 m_directManipulationHelper->update();
250}
251
253{
254 /* Only #DM_POINTERHITTEST can be the first message of input sequence of touch-pad input. */
255
256 if (!m_directManipulationHelper) {
257 return;
258 }
259
260 UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
261 POINTER_INPUT_TYPE pointerType;
262 if (GetPointerType(pointerId, &pointerType) && pointerType == PT_TOUCHPAD) {
263 m_directManipulationHelper->onPointerHitTest(pointerId);
264 }
265}
266
268{
269 if (!m_directManipulationHelper) {
270 return {0, 0, 0};
271 }
272
273 return m_directManipulationHelper->getTrackpadInfo();
274}
275
277{
278 if (m_hWnd) {
279 unregisterWindowAppUserModelProperties();
280 }
281
282 if (m_Bar) {
283 m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
284 m_Bar->Release();
285 m_Bar = nullptr;
286 }
287
288 closeWintab();
289
290 if (m_user32) {
291 FreeLibrary(m_user32);
292 m_user32 = nullptr;
293 }
294
295 if (m_customCursor) {
296 DestroyCursor(m_customCursor);
297 m_customCursor = nullptr;
298 }
299
300 if (m_hWnd != nullptr && m_hDC != nullptr && releaseNativeHandles()) {
301 ::ReleaseDC(m_hWnd, m_hDC);
302 m_hDC = nullptr;
303 }
304
305 if (m_hWnd) {
306 /* If this window is referenced by others as parent, clear that relation or windows will free
307 * the handle while we still reference it. */
308 for (GHOST_IWindow *iter_win : m_system->getWindowManager()->getWindows()) {
309 GHOST_WindowWin32 *iter_winwin = (GHOST_WindowWin32 *)iter_win;
310 if (iter_winwin->m_parentWindowHwnd == m_hWnd) {
311 ::SetWindowLongPtr(iter_winwin->m_hWnd, GWLP_HWNDPARENT, 0);
312 iter_winwin->m_parentWindowHwnd = 0;
313 }
314 }
315
316 if (m_dropTarget) {
317 /* Disable DragDrop. */
318 RevokeDragDrop(m_hWnd);
319 /* Release our reference of the DropTarget and it will delete itself eventually. */
320 m_dropTarget->Release();
321 m_dropTarget = nullptr;
322 }
323 ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, 0);
324 ::DestroyWindow(m_hWnd);
325 m_hWnd = 0;
326 }
327
328 delete m_directManipulationHelper;
329 m_directManipulationHelper = nullptr;
330}
331
333 DWORD dwStyle,
334 DWORD dwExStyle)
335{
336 /* Get Details of the closest monitor. */
337 HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
338 MONITORINFOEX monitor;
339 monitor.cbSize = sizeof(MONITORINFOEX);
340 monitor.dwFlags = 0;
341 GetMonitorInfo(hmonitor, &monitor);
342
343 /* Constrain requested size and position to fit within this monitor. */
344 LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
345 LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
346 win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width);
347 win_rect->right = win_rect->left + width;
348 win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
349 win_rect->bottom = win_rect->top + height;
350
351 /* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
352 GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
353 if (m_user32) {
354 fpAdjustWindowRectExForDpi = (GHOST_WIN32_AdjustWindowRectExForDpi)::GetProcAddress(
355 m_user32, "AdjustWindowRectExForDpi");
356 }
357
358 /* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
359 * correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
360 if (fpAdjustWindowRectExForDpi) {
361 UINT dpiX, dpiY;
362 GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
363 fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
364 }
365 else {
366 AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
367 }
368
369 /* But never allow a top position that can hide part of the title bar. */
370 win_rect->top = max(monitor.rcWork.top, win_rect->top);
371}
372
374{
375 return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0;
376}
377
379{
380 return m_hWnd;
381}
382
384{
385 return (void *)m_hWnd;
386}
387
388void GHOST_WindowWin32::setTitle(const char *title)
389{
390 wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
391 ::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
392 free(title_16);
393}
394
396{
397 std::wstring wtitle(::GetWindowTextLengthW(m_hWnd) + 1, L'\0');
398 ::GetWindowTextW(m_hWnd, &wtitle[0], wtitle.capacity());
399
400 std::string title(count_utf_8_from_16(wtitle.c_str()) + 1, '\0');
401 conv_utf_16_to_8(wtitle.c_str(), &title[0], title.capacity());
402
403 return title;
404}
405
407{
408 RECT rect;
409 ::GetWindowRect(m_hWnd, &rect);
410 bounds.m_b = rect.bottom;
411 bounds.m_l = rect.left;
412 bounds.m_r = rect.right;
413 bounds.m_t = rect.top;
414}
415
417{
418 RECT rect;
419 POINT coord;
420 if (!IsIconic(m_hWnd)) {
421 ::GetClientRect(m_hWnd, &rect);
422
423 coord.x = rect.left;
424 coord.y = rect.top;
425 ::ClientToScreen(m_hWnd, &coord);
426
427 bounds.m_l = coord.x;
428 bounds.m_t = coord.y;
429
430 coord.x = rect.right;
431 coord.y = rect.bottom;
432 ::ClientToScreen(m_hWnd, &coord);
433
434 bounds.m_r = coord.x;
435 bounds.m_b = coord.y;
436 }
437 else {
438 bounds.m_b = 0;
439 bounds.m_l = 0;
440 bounds.m_r = 0;
441 bounds.m_t = 0;
442 }
443}
444
446{
447 GHOST_TSuccess success;
448 GHOST_Rect cBnds, wBnds;
449 getClientBounds(cBnds);
450 if (cBnds.getWidth() != int32_t(width)) {
451 getWindowBounds(wBnds);
452 int cx = wBnds.getWidth() + width - cBnds.getWidth();
453 int cy = wBnds.getHeight();
454 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
457 }
458 else {
459 success = GHOST_kSuccess;
460 }
461 return success;
462}
463
465{
466 GHOST_TSuccess success;
467 GHOST_Rect cBnds, wBnds;
468 getClientBounds(cBnds);
469 if (cBnds.getHeight() != int32_t(height)) {
470 getWindowBounds(wBnds);
471 int cx = wBnds.getWidth();
472 int cy = wBnds.getHeight() + height - cBnds.getHeight();
473 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
476 }
477 else {
478 success = GHOST_kSuccess;
479 }
480 return success;
481}
482
484{
485 GHOST_TSuccess success;
486 GHOST_Rect cBnds, wBnds;
487 getClientBounds(cBnds);
488 if ((cBnds.getWidth() != int32_t(width)) || (cBnds.getHeight() != int32_t(height))) {
489 getWindowBounds(wBnds);
490 int cx = wBnds.getWidth() + width - cBnds.getWidth();
491 int cy = wBnds.getHeight() + height - cBnds.getHeight();
492 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
495 }
496 else {
497 success = GHOST_kSuccess;
498 }
499 return success;
500}
501
503{
504 if (::IsIconic(m_hWnd)) {
506 }
507 else if (::IsZoomed(m_hWnd)) {
508 LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
509 return (result & WS_CAPTION) ? GHOST_kWindowStateMaximized : GHOST_kWindowStateFullScreen;
510 }
512}
513
515 int32_t inY,
516 int32_t &outX,
517 int32_t &outY) const
518{
519 POINT point = {inX, inY};
520 ::ScreenToClient(m_hWnd, &point);
521 outX = point.x;
522 outY = point.y;
523}
524
526 int32_t inY,
527 int32_t &outX,
528 int32_t &outY) const
529{
530 POINT point = {inX, inY};
531 ::ClientToScreen(m_hWnd, &point);
532 outX = point.x;
533 outY = point.y;
534}
535
537{
538 GHOST_TWindowState curstate = getState();
539 LONG_PTR style = GetWindowLongPtr(m_hWnd, GWL_STYLE) | WS_CAPTION;
540 WINDOWPLACEMENT wp;
541 wp.length = sizeof(WINDOWPLACEMENT);
542 ::GetWindowPlacement(m_hWnd, &wp);
543
544 switch (state) {
546 wp.showCmd = SW_MINIMIZE;
547 break;
549 wp.showCmd = SW_SHOWMAXIMIZED;
550 break;
552 if (curstate != state && curstate != GHOST_kWindowStateMinimized) {
553 m_normal_state = curstate;
554 }
555 wp.showCmd = SW_SHOWMAXIMIZED;
556 wp.ptMaxPosition.x = 0;
557 wp.ptMaxPosition.y = 0;
558 style &= ~(WS_CAPTION | WS_MAXIMIZE);
559 break;
561 default:
562 if (curstate == GHOST_kWindowStateFullScreen &&
563 m_normal_state == GHOST_kWindowStateMaximized)
564 {
565 wp.showCmd = SW_SHOWMAXIMIZED;
566 m_normal_state = GHOST_kWindowStateNormal;
567 }
568 else {
569 wp.showCmd = SW_SHOWNORMAL;
570 }
571 break;
572 }
573 ::SetWindowLongPtr(m_hWnd, GWL_STYLE, style);
574 /* #SetWindowLongPtr Docs:
575 * Frame changes not visible until #SetWindowPos with #SWP_FRAMECHANGED. */
576 ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
577 return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
578}
579
581{
582 HWND hWndInsertAfter, hWndToRaise;
583
584 if (order == GHOST_kWindowOrderBottom) {
585 hWndInsertAfter = HWND_BOTTOM;
586 hWndToRaise = ::GetWindow(m_hWnd, GW_HWNDNEXT); /* the window to raise */
587 }
588 else {
591 }
592 hWndInsertAfter = HWND_TOP;
593 hWndToRaise = nullptr;
594 }
595
596 if (::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
597 return GHOST_kFailure;
598 }
599
600 if (hWndToRaise &&
601 ::SetWindowPos(hWndToRaise, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE)
602 {
603 return GHOST_kFailure;
604 }
605 return GHOST_kSuccess;
606}
607
609{
610 GHOST_TSuccess success;
611 if (m_hWnd) {
612 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
613 }
614 else {
615 success = GHOST_kFailure;
616 }
617 return success;
618}
619
620GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type)
621{
622 switch (type) {
623#ifdef WITH_VULKAN_BACKEND
624 case GHOST_kDrawingContextTypeVulkan: {
625 GHOST_Context *context = new GHOST_ContextVK(
626 false, m_hWnd, 1, 2, m_debug_context, m_preferred_device);
627 if (context->initializeDrawingContext()) {
628 return context;
629 }
630 delete context;
631 return nullptr;
632 }
633#endif
634
635#ifdef WITH_OPENGL_BACKEND
636 case GHOST_kDrawingContextTypeOpenGL: {
637 for (int minor = 6; minor >= 3; --minor) {
638 GHOST_Context *context = new GHOST_ContextWGL(
640 m_wantAlphaBackground,
641 m_hWnd,
642 m_hDC,
643 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
644 4,
645 minor,
646 (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
648
649 if (context->initializeDrawingContext()) {
650 return context;
651 }
652 delete context;
653 }
654 return nullptr;
655 }
656#endif
657
658 case GHOST_kDrawingContextTypeD3D: {
659 GHOST_Context *context = new GHOST_ContextD3D(false, m_hWnd);
660
661 if (context->initializeDrawingContext()) {
662 return context;
663 }
664 delete context;
665 return nullptr;
666 }
667
668 default:
669 /* Unsupported backend. */
670 return nullptr;
671 }
672}
673
675{
676 if (m_hasMouseCaptured) {
677 m_hasGrabMouse = false;
678 m_nPressedButtons = 0;
679 m_hasMouseCaptured = false;
680 }
681}
682
684{
685 return m_isDialog;
686}
687
689{
690 switch (event) {
691 case MousePressed:
692 m_nPressedButtons++;
693 break;
694 case MouseReleased:
695 if (m_nPressedButtons) {
696 m_nPressedButtons--;
697 }
698 break;
699 case OperatorGrab:
700 m_hasGrabMouse = true;
701 break;
702 case OperatorUngrab:
703 m_hasGrabMouse = false;
704 break;
705 }
706
707 if (!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured) {
708 ::ReleaseCapture();
709 m_hasMouseCaptured = false;
710 }
711 else if ((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured) {
712 ::SetCapture(m_hWnd);
713 m_hasMouseCaptured = true;
714 }
715}
716
718{
719 /* Convert GHOST cursor to Windows OEM cursor. */
720 HANDLE cursor = nullptr;
721 HMODULE module = ::GetModuleHandle(0);
722 uint32_t flags = LR_SHARED | LR_DEFAULTSIZE;
723 int cx = 0, cy = 0;
724
725 switch (shape) {
727 if (m_customCursor) {
728 return m_customCursor;
729 }
730 else {
731 return nullptr;
732 }
734 cursor = ::LoadImage(module, "arrowright_cursor", IMAGE_CURSOR, cx, cy, flags);
735 break;
737 cursor = ::LoadImage(module, "arrowleft_cursor", IMAGE_CURSOR, cx, cy, flags);
738 break;
740 cursor = ::LoadImage(module, "arrowup_cursor", IMAGE_CURSOR, cx, cy, flags);
741 break;
743 cursor = ::LoadImage(module, "arrowdown_cursor", IMAGE_CURSOR, cx, cy, flags);
744 break;
746 cursor = ::LoadImage(module, "splitv_cursor", IMAGE_CURSOR, cx, cy, flags);
747 break;
749 cursor = ::LoadImage(module, "splith_cursor", IMAGE_CURSOR, cx, cy, flags);
750 break;
752 cursor = ::LoadImage(module, "knife_cursor", IMAGE_CURSOR, cx, cy, flags);
753 break;
755 cursor = ::LoadImage(module, "eyedropper_cursor", IMAGE_CURSOR, cx, cy, flags);
756 break;
758 cursor = ::LoadImage(module, "zoomin_cursor", IMAGE_CURSOR, cx, cy, flags);
759 break;
761 cursor = ::LoadImage(module, "zoomout_cursor", IMAGE_CURSOR, cx, cy, flags);
762 break;
764 cursor = ::LoadImage(nullptr, IDC_SIZEALL, IMAGE_CURSOR, cx, cy, flags);
765 break;
767 cursor = ::LoadImage(module, "handopen_cursor", IMAGE_CURSOR, cx, cy, flags);
768 break;
770 cursor = ::LoadImage(module, "handclosed_cursor", IMAGE_CURSOR, cx, cy, flags);
771 break;
773 cursor = ::LoadImage(module, "handpoint_cursor", IMAGE_CURSOR, cx, cy, flags);
774 break;
776 cursor = ::LoadImage(module, "scrollnsew_cursor", IMAGE_CURSOR, cx, cy, flags);
777 break;
779 cursor = ::LoadImage(module, "scrollns_cursor", IMAGE_CURSOR, cx, cy, flags);
780 break;
782 cursor = ::LoadImage(module, "scrollew_cursor", IMAGE_CURSOR, cx, cy, flags);
783 break;
785 cursor = ::LoadImage(nullptr, IDC_HELP, IMAGE_CURSOR, cx, cy, flags);
786 break; /* Arrow and question mark */
788 cursor = ::LoadImage(nullptr, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags);
789 break; /* Hourglass */
791 cursor = ::LoadImage(nullptr, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags);
792 break; /* I-beam */
794 cursor = ::LoadImage(module, "cross_cursor", IMAGE_CURSOR, cx, cy, flags);
795 break; /* Standard Cross */
797 cursor = ::LoadImage(module, "crossA_cursor", IMAGE_CURSOR, cx, cy, flags);
798 break; /* Crosshair A */
800 cursor = ::LoadImage(module, "crossB_cursor", IMAGE_CURSOR, cx, cy, flags);
801 break; /* Diagonal Crosshair B */
803 cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags);
804 break; /* Minimal Crosshair C */
807 cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags);
808 break; /* Double-pointed arrow pointing north and south */
811 cursor = ::LoadImage(module, "moveew_cursor", IMAGE_CURSOR, cx, cy, flags);
812 break; /* Double-pointed arrow pointing west and east */
814 cursor = ::LoadImage(nullptr, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags);
815 break; /* Vertical arrow */
817 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
818 break;
820 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
821 break;
823 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
824 break;
826 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
827 break;
829 cursor = ::LoadImage(module, "pencil_cursor", IMAGE_CURSOR, cx, cy, flags);
830 break;
832 cursor = ::LoadImage(module, "eraser_cursor", IMAGE_CURSOR, cx, cy, flags);
833 break;
836 cursor = ::LoadImage(module, "forbidden_cursor", IMAGE_CURSOR, cx, cy, flags);
837 break; /* Slashed circle */
839 cursor = ::LoadImage(module, "handle_left_cursor", IMAGE_CURSOR, cx, cy, flags);
840 break;
842 cursor = ::LoadImage(module, "handle_right_cursor", IMAGE_CURSOR, cx, cy, flags);
843 break;
845 cursor = ::LoadImage(module, "handle_both_cursor", IMAGE_CURSOR, cx, cy, flags);
846 break;
847
849 cursor = nullptr;
850 break;
851 default:
852 return nullptr;
853 }
854
855 if (cursor == nullptr) {
856 cursor = ::LoadImage(nullptr, IDC_ARROW, IMAGE_CURSOR, cx, cy, flags);
857 }
858
859 return (HCURSOR)cursor;
860}
861
863{
864 if (!visible) {
865 while (::ShowCursor(FALSE) >= 0) {
866 /* Pass. */
867 }
868 }
869 else {
870 while (::ShowCursor(TRUE) < 0) {
871 /* Pass. */
872 }
873 }
874
875 HCURSOR cursor = getStandardCursor(shape);
876 if (cursor == nullptr) {
878 }
879 ::SetCursor(cursor);
880}
881
882GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
883{
884 if (::GetForegroundWindow() == m_hWnd) {
885 loadCursor(visible, getCursorShape());
886 }
887
888 return GHOST_kSuccess;
889}
890
891GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
892{
893 if (mode != GHOST_kGrabDisable) {
894 if (mode != GHOST_kGrabNormal) {
896 setCursorGrabAccum(0, 0);
897
898 if (mode == GHOST_kGrabHide) {
899 setWindowCursorVisibility(false);
900 }
901 }
903 }
904 else {
907 setWindowCursorVisibility(true);
908 }
910 /* Use to generate a mouse move event, otherwise the last event
911 * blender gets can be outside the screen causing menus not to show
912 * properly unless the user moves the mouse. */
913 int32_t pos[2];
914 m_system->getCursorPosition(pos[0], pos[1]);
915 m_system->setCursorPosition(pos[0], pos[1]);
916 }
917
918 /* Almost works without but important otherwise the mouse GHOST location
919 * can be incorrect on exit. */
920 setCursorGrabAccum(0, 0);
921 m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
923 }
924
925 return GHOST_kSuccess;
926}
927
928GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
929{
930 if (::GetForegroundWindow() == m_hWnd) {
931 loadCursor(getCursorVisibility(), cursorShape);
932 }
933
934 return GHOST_kSuccess;
935}
936
937GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorShape)
938{
939 return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
940}
941
943 std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM /*lParam*/)
944{
945 int32_t pointerId = GET_POINTERID_WPARAM(wParam);
946 int32_t isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
948 uint32_t outCount = 0;
949
950 if (!(GetPointerPenInfoHistory(pointerId, &outCount, nullptr))) {
951 return GHOST_kFailure;
952 }
953
954 std::vector<POINTER_PEN_INFO> pointerPenInfo(outCount);
955 outPointerInfo.resize(outCount);
956
957 if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
958 return GHOST_kFailure;
959 }
960
961 for (uint32_t i = 0; i < outCount; i++) {
962 POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo;
963 /* Obtain the basic information from the event. */
964 outPointerInfo[i].pointerId = pointerId;
965 outPointerInfo[i].isPrimary = isPrimary;
966
967 switch (pointerApiInfo.ButtonChangeType) {
968 case POINTER_CHANGE_FIRSTBUTTON_DOWN:
969 case POINTER_CHANGE_FIRSTBUTTON_UP:
970 outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft;
971 break;
972 case POINTER_CHANGE_SECONDBUTTON_DOWN:
973 case POINTER_CHANGE_SECONDBUTTON_UP:
974 outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight;
975 break;
976 case POINTER_CHANGE_THIRDBUTTON_DOWN:
977 case POINTER_CHANGE_THIRDBUTTON_UP:
978 outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle;
979 break;
980 case POINTER_CHANGE_FOURTHBUTTON_DOWN:
981 case POINTER_CHANGE_FOURTHBUTTON_UP:
982 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4;
983 break;
984 case POINTER_CHANGE_FIFTHBUTTON_DOWN:
985 case POINTER_CHANGE_FIFTHBUTTON_UP:
986 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5;
987 break;
988 default:
989 break;
990 }
991
992 outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation;
993 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus;
994 outPointerInfo[i].tabletData.Pressure = 1.0f;
995 outPointerInfo[i].tabletData.Xtilt = 0.0f;
996 outPointerInfo[i].tabletData.Ytilt = 0.0f;
997 outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount);
998
999 if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) {
1000 outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f;
1001 }
1002
1003 if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) {
1004 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser;
1005 }
1006
1007 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) {
1008 outPointerInfo[i].tabletData.Xtilt = fmin(fabs(pointerPenInfo[i].tiltX / 90.0f), 1.0f);
1009 }
1010
1011 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) {
1012 outPointerInfo[i].tabletData.Ytilt = fmin(fabs(pointerPenInfo[i].tiltY / 90.0f), 1.0f);
1013 }
1014 }
1015
1016 if (!outPointerInfo.empty()) {
1017 m_lastPointerTabletData = outPointerInfo.back().tabletData;
1018 }
1019
1020 return GHOST_kSuccess;
1021}
1022
1024{
1025 m_lastPointerTabletData = GHOST_TABLET_DATA_NONE;
1026}
1027
1029{
1030 return m_wintab;
1031}
1032
1034{
1035 if (!m_wintab) {
1036 WINTAB_PRINTF("Loading Wintab for window %p\n", m_hWnd);
1037 if (m_wintab = GHOST_Wintab::loadWintab(m_hWnd)) {
1038 if (enable) {
1039 m_wintab->enable();
1040
1041 /* Focus Wintab if cursor is inside this window. This ensures Wintab is enabled when the
1042 * tablet is used to change the Tablet API. */
1043 int32_t x, y;
1044 if (m_system->getCursorPosition(x, y)) {
1045 GHOST_Rect rect;
1046 getClientBounds(rect);
1047
1048 if (rect.isInside(x, y)) {
1049 m_wintab->gainFocus();
1050 }
1051 }
1052 }
1053 }
1054 }
1055}
1056
1058{
1059 WINTAB_PRINTF("Closing Wintab for window %p\n", m_hWnd);
1060 delete m_wintab;
1061 m_wintab = nullptr;
1062}
1063
1065{
1066 if (m_system->getTabletAPI() == api) {
1067 return true;
1068 }
1069 else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
1070 if (m_wintab && m_wintab->devicesPresent()) {
1071 return api == GHOST_kTabletWintab;
1072 }
1073 else {
1074 return api == GHOST_kTabletWinPointer;
1075 }
1076 }
1077 else {
1078 return false;
1079 }
1080}
1081
1083{
1085 return m_wintab ? m_wintab->getLastTabletData() : GHOST_TABLET_DATA_NONE;
1086 }
1087 else {
1088 return m_lastPointerTabletData;
1089 }
1090}
1091
1093{
1094 DWORD lightMode;
1095 DWORD pcbData = sizeof(lightMode);
1096 if (RegGetValueW(HKEY_CURRENT_USER,
1097 L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\",
1098 L"AppsUseLightTheme",
1099 RRF_RT_REG_DWORD,
1100 nullptr,
1101 &lightMode,
1102 &pcbData) == ERROR_SUCCESS)
1103 {
1104 BOOL DarkMode = !lightMode;
1105
1106 /* `20 == DWMWA_USE_IMMERSIVE_DARK_MODE` in Windows 11 SDK.
1107 * This value was undocumented for Windows 10 versions 2004 and later,
1108 * supported for Windows 11 Build 22000 and later. */
1109 DwmSetWindowAttribute(this->m_hWnd, 20, &DarkMode, sizeof(DarkMode));
1110 }
1111}
1112
1114{
1115 if (m_directManipulationHelper) {
1116 m_directManipulationHelper->setDPI(getDPIHint());
1117 }
1118}
1119
1121{
1122 if (m_user32) {
1123 GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow)::GetProcAddress(
1124 m_user32, "GetDpiForWindow");
1125
1126 if (fpGetDpiForWindow) {
1127 return fpGetDpiForWindow(this->m_hWnd);
1128 }
1129 }
1130
1131 return USER_DEFAULT_SCREEN_DPI;
1132}
1133
1136{
1137 ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1138 ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1139 ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1140 return ch;
1141}
1142
1143#if 0 /* UNUSED */
1146{
1147 shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1148 shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1149 shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1150 shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1151 return shrt;
1152}
1153#endif
1154
1155GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(uint8_t *bitmap,
1156 uint8_t *mask,
1157 int sizeX,
1158 int sizeY,
1159 int hotX,
1160 int hotY,
1161 bool /*canInvertColor*/)
1162{
1163 uint32_t andData[32];
1164 uint32_t xorData[32];
1165 uint32_t fullBitRow, fullMaskRow;
1166 int x, y, cols;
1167
1168 cols = sizeX / 8; /* Number of whole bytes per row (width of bitmap/mask). */
1169 if (sizeX % 8) {
1170 cols++;
1171 }
1172
1173 if (m_customCursor) {
1174 DestroyCursor(m_customCursor);
1175 m_customCursor = nullptr;
1176 }
1177
1178 memset(&andData, 0xFF, sizeof(andData));
1179 memset(&xorData, 0, sizeof(xorData));
1180
1181 for (y = 0; y < sizeY; y++) {
1182 fullBitRow = 0;
1183 fullMaskRow = 0;
1184 for (x = cols - 1; x >= 0; x--) {
1185 fullBitRow <<= 8;
1186 fullMaskRow <<= 8;
1187 fullBitRow |= uns8ReverseBits(bitmap[cols * y + x]);
1188 fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1189 }
1190 xorData[y] = fullBitRow & fullMaskRow;
1191 andData[y] = ~fullMaskRow;
1192 }
1193
1194 m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1195 if (!m_customCursor) {
1196 return GHOST_kFailure;
1197 }
1198
1199 if (::GetForegroundWindow() == m_hWnd) {
1201 }
1202
1203 return GHOST_kSuccess;
1204}
1205
1207{
1208 /* #SetProgressValue sets state to #TBPF_NORMAL automatically. */
1209 if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000)) {
1210 return GHOST_kSuccess;
1211 }
1212
1213 return GHOST_kFailure;
1214}
1215
1217{
1218 if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS)) {
1219 return GHOST_kSuccess;
1220 }
1221
1222 return GHOST_kFailure;
1223}
1224
1225#ifdef WITH_INPUT_IME
1226void GHOST_WindowWin32::beginIME(int32_t x, int32_t y, int32_t /*w*/, int32_t h, bool completed)
1227{
1228 m_imeInput.BeginIME(m_hWnd, GHOST_Rect(x, y - h, x, y), completed);
1229}
1230
1231void GHOST_WindowWin32::endIME()
1232{
1233 m_imeInput.EndIME(m_hWnd);
1234}
1235#endif /* WITH_INPUT_IME */
1236
1237void GHOST_WindowWin32::registerWindowAppUserModelProperties()
1238{
1239 IPropertyStore *pstore;
1240 char blender_path[MAX_PATH];
1241 wchar_t shell_command[MAX_PATH];
1242
1243 /* Find the current executable, and see if it's blender.exe if not bail out. */
1244 GetModuleFileName(0, blender_path, sizeof(blender_path));
1245 char *blender_app = strstr(blender_path, "blender.exe");
1246 if (!blender_app) {
1247 return;
1248 }
1249
1250 HRESULT hr = SHGetPropertyStoreForWindow(m_hWnd, IID_PPV_ARGS(&pstore));
1251 if (!SUCCEEDED(hr)) {
1252 return;
1253 }
1254
1255 /* Set the launcher as the shell command so the console window will not flash.
1256 * when people pin blender to the taskbar. */
1257 strcpy(blender_app, "blender-launcher.exe");
1258 wsprintfW(shell_command, L"\"%S\"", blender_path);
1259 UTF16_ENCODE(BLENDER_WIN_APPID);
1260 UTF16_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1261 PROPVARIANT propvar;
1262 hr = InitPropVariantFromString(BLENDER_WIN_APPID_16, &propvar);
1263 hr = pstore->SetValue(PKEY_AppUserModel_ID, propvar);
1264 hr = InitPropVariantFromString(shell_command, &propvar);
1265 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, propvar);
1266 hr = InitPropVariantFromString(BLENDER_WIN_APPID_FRIENDLY_NAME_16, &propvar);
1267 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, propvar);
1268 pstore->Release();
1269 UTF16_UN_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1270 UTF16_UN_ENCODE(BLENDER_WIN_APPID);
1271}
1272
1273/* as per MSDN: Any property not cleared before closing the window, will be leaked and NOT be
1274 * returned to the OS. */
1275void GHOST_WindowWin32::unregisterWindowAppUserModelProperties()
1276{
1277 IPropertyStore *pstore;
1278 HRESULT hr = SHGetPropertyStoreForWindow(m_hWnd, IID_PPV_ARGS(&pstore));
1279 if (SUCCEEDED(hr)) {
1280 PROPVARIANT value;
1281 PropVariantInit(&value);
1282 pstore->SetValue(PKEY_AppUserModel_ID, value);
1283 pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, value);
1284 pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, value);
1285 pstore->Release();
1286 }
1287}
void BLI_kdtree_nd_ free(KDTree *tree)
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FALSE
#define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY
@ TBPF_NOPROGRESS
const GUID CLSID_TaskbarList
GHOST_TWindowState
@ GHOST_kWindowStateMinimized
@ GHOST_kWindowStateMaximized
@ GHOST_kWindowStateNormal
@ GHOST_kWindowStateFullScreen
GHOST_TStandardCursor
@ GHOST_kStandardCursorLeftHandle
@ GHOST_kStandardCursorHandClosed
@ GHOST_kStandardCursorHandOpen
@ GHOST_kStandardCursorBottomLeftCorner
@ GHOST_kStandardCursorZoomIn
@ GHOST_kStandardCursorVerticalSplit
@ GHOST_kStandardCursorHelp
@ GHOST_kStandardCursorWait
@ GHOST_kStandardCursorRightHandle
@ GHOST_kStandardCursorHorizontalSplit
@ GHOST_kStandardCursorTopSide
@ GHOST_kStandardCursorStop
@ GHOST_kStandardCursorCrosshair
@ GHOST_kStandardCursorCustom
@ GHOST_kStandardCursorNSEWScroll
@ GHOST_kStandardCursorLeftRight
@ GHOST_kStandardCursorPencil
@ GHOST_kStandardCursorNSScroll
@ GHOST_kStandardCursorCrosshairA
@ GHOST_kStandardCursorUpDown
@ GHOST_kStandardCursorUpArrow
@ GHOST_kStandardCursorHandPoint
@ GHOST_kStandardCursorBottomSide
@ GHOST_kStandardCursorBothHandles
@ GHOST_kStandardCursorTopLeftCorner
@ GHOST_kStandardCursorEyedropper
@ GHOST_kStandardCursorKnife
@ GHOST_kStandardCursorMove
@ GHOST_kStandardCursorCrosshairB
@ GHOST_kStandardCursorBottomRightCorner
@ GHOST_kStandardCursorDownArrow
@ GHOST_kStandardCursorEraser
@ GHOST_kStandardCursorDefault
@ GHOST_kStandardCursorEWScroll
@ GHOST_kStandardCursorRightArrow
@ GHOST_kStandardCursorTopRightCorner
@ GHOST_kStandardCursorDestroy
@ GHOST_kStandardCursorCrosshairC
@ GHOST_kStandardCursorZoomOut
@ GHOST_kStandardCursorLeftSide
@ GHOST_kStandardCursorText
@ GHOST_kStandardCursorLeftArrow
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
@ GHOST_kTabletModeEraser
@ GHOST_kTabletModeStylus
GHOST_TDrawingContextType
GHOST_TWindowOrder
@ GHOST_kWindowOrderBottom
GHOST_TSuccess
Definition GHOST_Types.h:87
@ GHOST_kFailure
Definition GHOST_Types.h:87
@ GHOST_kSuccess
Definition GHOST_Types.h:87
GHOST_TGrabCursorMode
@ GHOST_kGrabDisable
@ GHOST_kGrabHide
@ GHOST_kGrabNormal
@ GHOST_kButtonMaskRight
@ GHOST_kButtonMaskButton4
@ GHOST_kButtonMaskLeft
@ GHOST_kButtonMaskButton5
@ GHOST_kButtonMaskMiddle
GHOST_TTabletAPI
@ GHOST_kTabletAutomatic
@ GHOST_kTabletWinPointer
@ GHOST_kTabletWintab
static uint16_t uns16ReverseBits(uint16_t shrt)
#define GET_POINTERID_WPARAM(wParam)
static uint8_t uns8ReverseBits(uint8_t ch)
__declspec(dllexport) DWORD NvOptimusEnablement=0x00000001
UINT(API * GHOST_WIN32_GetDpiForWindow)(HWND)
BOOL(API * GHOST_WIN32_AdjustWindowRectExForDpi)(LPRECT lpRect, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle, UINT dpi)
GHOST_MouseCaptureEventWin32
@ MousePressed
@ OperatorUngrab
@ MouseReleased
@ OperatorGrab
#define WINTAB_PRINTF(x,...)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
void onPointerHitTest(UINT32 pointerId)
static GHOST_DirectManipulationHelper * create(HWND hWnd, uint16_t dpi)
static GHOST_ISystem * getSystem()
virtual bool isInside(int32_t x, int32_t y) const
int32_t m_l
int32_t m_r
virtual int32_t getHeight() const
virtual int32_t getWidth() const
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y)
GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const
uint64_t performanceCounterToMillis(__int64 perf_ticks) const
GHOST_TTabletAPI getTabletAPI()
GHOST_WindowManager * getWindowManager() const
const std::vector< GHOST_IWindow * > & getWindows() const
GHOST_TSuccess invalidate()
GHOST_TSuccess setOrder(GHOST_TWindowOrder order)
uint16_t getDPIHint() override
GHOST_TTrackpadInfo getTrackpadInfo()
GHOST_TSuccess setProgressBar(float progress)
void setTitle(const char *title)
std::string getTitle() const
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height)
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const
bool usingTabletAPI(GHOST_TTabletAPI api) const
GHOST_TSuccess getPointerInfo(std::vector< GHOST_PointerInfoWin32 > &outPointerInfo, WPARAM wParam, LPARAM lParam)
GHOST_TSuccess setClientHeight(uint32_t height)
void loadWintab(bool enable)
GHOST_TabletData getTabletData()
GHOST_Wintab * getWintab() const
HCURSOR getStandardCursor(GHOST_TStandardCursor shape) const
void updateMouseCapture(GHOST_MouseCaptureEventWin32 event)
GHOST_TSuccess setClientWidth(uint32_t width)
GHOST_TSuccess setState(GHOST_TWindowState state)
void getWindowBounds(GHOST_Rect &bounds) const
void getClientBounds(GHOST_Rect &bounds) const
GHOST_WindowWin32(GHOST_SystemWin32 *system, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, GHOST_TDrawingContextType type, bool wantStereoVisual, bool alphaBackground, GHOST_WindowWin32 *parentWindow, bool is_debug, bool dialog, const GHOST_GPUDevice &preferred_device)
void onPointerHitTest(WPARAM wParam)
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
GHOST_TSuccess endProgressBar()
GHOST_TWindowState getState() const
void * getOSWindow() const
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
GHOST_Rect m_cursorGrabBounds
void setCursorGrabAccum(int32_t x, int32_t y)
GHOST_TGrabCursorMode m_cursorGrab
bool m_wantStereoVisual
int32_t m_cursorGrabInitPos[2]
GHOST_TStandardCursor getCursorShape() const override
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override
GHOST_TSuccess releaseNativeHandles()
bool getCursorVisibility() const override
virtual bool getValid() const override
GHOST_TabletData getLastTabletData()
bool devicesPresent()
static GHOST_Wintab * loadWintab(HWND hwnd)
virtual HRESULT STDMETHODCALLTYPE SetProgressState(HWND hwnd, TBPFLAG tbpFlags)=0
virtual HRESULT STDMETHODCALLTYPE SetProgressValue(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal)=0
#define NULL
uint top
ccl_device_inline float2 fabs(const float2 a)
static ulong state[N]
static int left
#define L
static struct PyModuleDef module
Definition python.cpp:991
#define min(a, b)
Definition sort.c:32
unsigned short uint16_t
Definition stdint.h:79
unsigned int uint32_t
Definition stdint.h:80
signed int int32_t
Definition stdint.h:77
unsigned char uint8_t
Definition stdint.h:78
float max
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)
Definition utfconv.cc:292
size_t count_utf_8_from_16(const wchar_t *string16)
Definition utfconv.cc:11
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8)
Definition utfconv.cc:116
#define UTF16_ENCODE(in8str)
Definition utfconv.hh:80
#define UTF16_UN_ENCODE(in8str)
Definition utfconv.hh:84