Blender V4.5
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
8
9#include <algorithm>
10
11#include "GHOST_ContextD3D.hh"
12#include "GHOST_ContextNone.hh"
14#include "GHOST_SystemWin32.hh"
16#include "GHOST_WindowWin32.hh"
17#include "utf_winfunc.hh"
18#include "utfconv.hh"
19
20#ifdef WITH_OPENGL_BACKEND
21# include "GHOST_ContextWGL.hh"
22#endif
23#ifdef WITH_VULKAN_BACKEND
24# include "GHOST_ContextVK.hh"
25#endif
26
27#ifdef WIN32
28# include "BLI_path_utils.hh"
29#endif
30
31#include <Dwmapi.h>
32
33#include <assert.h>
34#include <math.h>
35#include <propkey.h>
36#include <propvarutil.h>
37#include <shellapi.h>
38#include <shellscalingapi.h>
39#include <string.h>
40#include <windowsx.h>
41
42#ifndef GET_POINTERID_WPARAM
43# define GET_POINTERID_WPARAM(wParam) (LOWORD(wParam))
44#endif /* GET_POINTERID_WPARAM */
45
46const wchar_t *GHOST_WindowWin32::s_windowClassName = L"GHOST_WindowClass";
47const int GHOST_WindowWin32::s_maxTitleLength = 128;
48
49/* force NVidia OPTIMUS to used dedicated graphics */
50extern "C" {
51__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
52}
53
55 const char *title,
58 uint32_t width,
59 uint32_t height,
62 bool wantStereoVisual,
63 GHOST_WindowWin32 *parentwindow,
64 bool is_debug,
65 bool dialog,
66 const GHOST_GPUDevice &preferred_device)
67 : GHOST_Window(width, height, state, wantStereoVisual, false),
70 m_system(system),
71 m_dropTarget(nullptr),
72 m_hWnd(0),
73 m_hDC(0),
74 m_isDialog(dialog),
75 m_preferred_device(preferred_device),
76 m_hasMouseCaptured(false),
77 m_hasGrabMouse(false),
78 m_nPressedButtons(0),
79 m_customCursor(0),
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) {
197 nCmdShow = SW_SHOWMAXIMIZED;
198 break;
200 nCmdShow = (m_system->m_windowFocus) ? SW_SHOWMINIMIZED : SW_SHOWMINNOACTIVE;
201 break;
203 default:
204 nCmdShow = (m_system->m_windowFocus) ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
205 break;
206 }
207
208 ThemeRefresh();
209
210 ::ShowWindow(m_hWnd, nCmdShow);
211
212 /* Initialize WINTAB. */
213 if (system->getTabletAPI() != GHOST_kTabletWinPointer) {
215 }
216
217 /* Allow the showing of a progress bar on the taskbar. */
218 CoCreateInstance(
219 CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar);
220
221 /* Initialize Direct Manipulation. */
222 m_directManipulationHelper = GHOST_DirectManipulationHelper::create(m_hWnd, getDPIHint());
223}
224
226{
227 if (!m_directManipulationHelper) {
228 return;
229 }
230
231 m_directManipulationHelper->update();
232}
233
235{
236 /* Only #DM_POINTERHITTEST can be the first message of input sequence of touch-pad input. */
237
238 if (!m_directManipulationHelper) {
239 return;
240 }
241
242 UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
243 POINTER_INPUT_TYPE pointerType;
244 if (GetPointerType(pointerId, &pointerType) && pointerType == PT_TOUCHPAD) {
245 m_directManipulationHelper->onPointerHitTest(pointerId);
246 }
247}
248
250{
251 if (!m_directManipulationHelper) {
252 return {0, 0, 0};
253 }
254
255 return m_directManipulationHelper->getTrackpadInfo();
256}
257
259{
260 if (m_hWnd) {
261 unregisterWindowAppUserModelProperties();
262 }
263
264 if (m_Bar) {
265 m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS);
266 m_Bar->Release();
267 m_Bar = nullptr;
268 }
269
270 closeWintab();
271
272 if (m_user32) {
273 FreeLibrary(m_user32);
274 m_user32 = nullptr;
275 }
276
277 if (m_customCursor) {
278 DestroyCursor(m_customCursor);
279 m_customCursor = nullptr;
280 }
281
282 if (m_hWnd != nullptr && m_hDC != nullptr && releaseNativeHandles()) {
283 ::ReleaseDC(m_hWnd, m_hDC);
284 m_hDC = nullptr;
285 }
286
287 if (m_hWnd) {
288 /* If this window is referenced by others as parent, clear that relation or windows will free
289 * the handle while we still reference it. */
290 for (GHOST_IWindow *iter_win : m_system->getWindowManager()->getWindows()) {
291 GHOST_WindowWin32 *iter_winwin = (GHOST_WindowWin32 *)iter_win;
292 if (iter_winwin->m_parentWindowHwnd == m_hWnd) {
293 ::SetWindowLongPtr(iter_winwin->m_hWnd, GWLP_HWNDPARENT, 0);
294 iter_winwin->m_parentWindowHwnd = 0;
295 }
296 }
297
298 if (m_dropTarget) {
299 /* Disable DragDrop. */
300 RevokeDragDrop(m_hWnd);
301 /* Release our reference of the DropTarget and it will delete itself eventually. */
302 m_dropTarget->Release();
303 m_dropTarget = nullptr;
304 }
305 ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, 0);
306 ::DestroyWindow(m_hWnd);
307 m_hWnd = 0;
308 }
309
310 delete m_directManipulationHelper;
311 m_directManipulationHelper = nullptr;
312}
313
315 DWORD dwStyle,
316 DWORD dwExStyle)
317{
318 /* Get Details of the closest monitor. */
319 HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
320 MONITORINFOEX monitor;
321 monitor.cbSize = sizeof(MONITORINFOEX);
322 monitor.dwFlags = 0;
323 GetMonitorInfo(hmonitor, &monitor);
324
325 /* Constrain requested size and position to fit within this monitor. */
326 LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
327 LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
328 win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width);
329 win_rect->right = win_rect->left + width;
330 win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
331 win_rect->bottom = win_rect->top + height;
332
333 /* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
334 GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
335 if (m_user32) {
336 fpAdjustWindowRectExForDpi = (GHOST_WIN32_AdjustWindowRectExForDpi)::GetProcAddress(
337 m_user32, "AdjustWindowRectExForDpi");
338 }
339
340 /* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
341 * correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
342 if (fpAdjustWindowRectExForDpi) {
343 UINT dpiX, dpiY;
344 GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
345 fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
346 }
347 else {
348 AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
349 }
350
351 /* But never allow a top position that can hide part of the title bar. */
352 win_rect->top = max(monitor.rcWork.top, win_rect->top);
353}
354
356{
357 return GHOST_Window::getValid() && m_hWnd != 0 && m_hDC != 0;
358}
359
361{
362 return m_hWnd;
363}
364
366{
367 return (void *)m_hWnd;
368}
369
370void GHOST_WindowWin32::setTitle(const char *title)
371{
372 wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
373 ::SetWindowTextW(m_hWnd, (wchar_t *)title_16);
374 free(title_16);
375}
376
378{
379 std::wstring wtitle(::GetWindowTextLengthW(m_hWnd) + 1, L'\0');
380 ::GetWindowTextW(m_hWnd, &wtitle[0], wtitle.capacity());
381
382 std::string title(count_utf_8_from_16(wtitle.c_str()) + 1, '\0');
383 conv_utf_16_to_8(wtitle.c_str(), &title[0], title.capacity());
384
385 return title;
386}
387
389{
390 /* DWMWINDOWATTRIBUTE::DWMWA_CAPTION_COLOR */
391 constexpr DWORD caption_color_attr = 35;
392
394 const float *color = m_windowDecorationStyleSettings.colored_titlebar_bg_color;
395 const COLORREF colorref = RGB(
396 char(color[0] * 255.0f), char(color[1] * 255.0f), char(color[2] * 255.0f));
397 if (!SUCCEEDED(DwmSetWindowAttribute(m_hWnd, caption_color_attr, &colorref, sizeof(colorref))))
398 {
399 return GHOST_kFailure;
400 }
401 }
402 return GHOST_kSuccess;
403}
404
406{
407 RECT rect;
408 ::GetWindowRect(m_hWnd, &rect);
409 bounds.m_b = rect.bottom;
410 bounds.m_l = rect.left;
411 bounds.m_r = rect.right;
412 bounds.m_t = rect.top;
413}
414
416{
417 RECT rect;
418 POINT coord;
419 if (!IsIconic(m_hWnd)) {
420 ::GetClientRect(m_hWnd, &rect);
421
422 coord.x = rect.left;
423 coord.y = rect.top;
424 ::ClientToScreen(m_hWnd, &coord);
425
426 bounds.m_l = coord.x;
427 bounds.m_t = coord.y;
428
429 coord.x = rect.right;
430 coord.y = rect.bottom;
431 ::ClientToScreen(m_hWnd, &coord);
432
433 bounds.m_r = coord.x;
434 bounds.m_b = coord.y;
435 }
436 else {
437 bounds.m_b = 0;
438 bounds.m_l = 0;
439 bounds.m_r = 0;
440 bounds.m_t = 0;
441 }
442}
443
445{
446 GHOST_TSuccess success;
447 GHOST_Rect cBnds, wBnds;
448 getClientBounds(cBnds);
449 if (cBnds.getWidth() != int32_t(width)) {
450 getWindowBounds(wBnds);
451 int cx = wBnds.getWidth() + width - cBnds.getWidth();
452 int cy = wBnds.getHeight();
453 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
456 }
457 else {
458 success = GHOST_kSuccess;
459 }
460 return success;
461}
462
464{
465 GHOST_TSuccess success;
466 GHOST_Rect cBnds, wBnds;
467 getClientBounds(cBnds);
468 if (cBnds.getHeight() != int32_t(height)) {
469 getWindowBounds(wBnds);
470 int cx = wBnds.getWidth();
471 int cy = wBnds.getHeight() + height - cBnds.getHeight();
472 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
475 }
476 else {
477 success = GHOST_kSuccess;
478 }
479 return success;
480}
481
482GHOST_TSuccess GHOST_WindowWin32::setClientSize(uint32_t width, uint32_t height)
483{
484 GHOST_TSuccess success;
485 GHOST_Rect cBnds, wBnds;
486 getClientBounds(cBnds);
487 if ((cBnds.getWidth() != int32_t(width)) || (cBnds.getHeight() != int32_t(height))) {
488 getWindowBounds(wBnds);
489 int cx = wBnds.getWidth() + width - cBnds.getWidth();
490 int cy = wBnds.getHeight() + height - cBnds.getHeight();
491 success = ::SetWindowPos(m_hWnd, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
494 }
495 else {
496 success = GHOST_kSuccess;
497 }
498 return success;
499}
500
502{
503 if (::IsIconic(m_hWnd)) {
505 }
506 else if (::IsZoomed(m_hWnd)) {
507 LONG_PTR result = ::GetWindowLongPtr(m_hWnd, GWL_STYLE);
509 }
511}
512
514 int32_t inY,
515 int32_t &outX,
516 int32_t &outY) const
517{
518 POINT point = {inX, inY};
519 ::ScreenToClient(m_hWnd, &point);
520 outX = point.x;
521 outY = point.y;
522}
523
525 int32_t inY,
526 int32_t &outX,
527 int32_t &outY) const
528{
529 POINT point = {inX, inY};
530 ::ClientToScreen(m_hWnd, &point);
531 outX = point.x;
532 outY = point.y;
533}
534
536{
537 GHOST_TWindowState curstate = getState();
538 LONG_PTR style = GetWindowLongPtr(m_hWnd, GWL_STYLE) | WS_CAPTION;
539 WINDOWPLACEMENT wp;
540 wp.length = sizeof(WINDOWPLACEMENT);
541 ::GetWindowPlacement(m_hWnd, &wp);
542
543 switch (state) {
545 wp.showCmd = SW_MINIMIZE;
546 break;
548 wp.showCmd = SW_SHOWMAXIMIZED;
549 break;
551 if (curstate != state && curstate != GHOST_kWindowStateMinimized) {
552 m_normal_state = curstate;
553 }
554 wp.showCmd = SW_SHOWMAXIMIZED;
555 wp.ptMaxPosition.x = 0;
556 wp.ptMaxPosition.y = 0;
557 style &= ~(WS_CAPTION | WS_MAXIMIZE);
558 break;
560 default:
561 if (curstate == GHOST_kWindowStateFullScreen &&
562 m_normal_state == GHOST_kWindowStateMaximized)
563 {
564 wp.showCmd = SW_SHOWMAXIMIZED;
565 m_normal_state = GHOST_kWindowStateNormal;
566 }
567 else {
568 wp.showCmd = SW_SHOWNORMAL;
569 }
570 break;
571 }
572 ::SetWindowLongPtr(m_hWnd, GWL_STYLE, style);
573 /* #SetWindowLongPtr Docs:
574 * Frame changes not visible until #SetWindowPos with #SWP_FRAMECHANGED. */
575 ::SetWindowPos(m_hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
576 return ::SetWindowPlacement(m_hWnd, &wp) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
577}
578
580{
581 HWND hWndInsertAfter, hWndToRaise;
582
583 if (order == GHOST_kWindowOrderBottom) {
584 hWndInsertAfter = HWND_BOTTOM;
585 hWndToRaise = ::GetWindow(m_hWnd, GW_HWNDNEXT); /* the window to raise */
586 }
587 else {
590 }
591 hWndInsertAfter = HWND_TOP;
592 hWndToRaise = nullptr;
593 }
594
595 if (::SetWindowPos(m_hWnd, hWndInsertAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE) {
596 return GHOST_kFailure;
597 }
598
599 if (hWndToRaise &&
600 ::SetWindowPos(hWndToRaise, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE) == FALSE)
601 {
602 return GHOST_kFailure;
603 }
604 return GHOST_kSuccess;
605}
606
608{
609 GHOST_TSuccess success;
610 if (m_hWnd) {
611 success = ::InvalidateRect(m_hWnd, 0, FALSE) != 0 ? GHOST_kSuccess : GHOST_kFailure;
612 }
613 else {
614 success = GHOST_kFailure;
615 }
616 return success;
617}
618
619GHOST_Context *GHOST_WindowWin32::newDrawingContext(GHOST_TDrawingContextType type)
620{
621 switch (type) {
622#ifdef WITH_VULKAN_BACKEND
623 case GHOST_kDrawingContextTypeVulkan: {
624 GHOST_Context *context = new GHOST_ContextVK(
625 false, m_hWnd, 1, 2, m_debug_context, m_preferred_device);
626 if (context->initializeDrawingContext()) {
627 return context;
628 }
629 delete context;
630 return nullptr;
631 }
632#endif
633
634#ifdef WITH_OPENGL_BACKEND
635 case GHOST_kDrawingContextTypeOpenGL: {
636 for (int minor = 6; minor >= 3; --minor) {
637 GHOST_Context *context = new GHOST_ContextWGL(
639 false,
640 m_hWnd,
641 m_hDC,
642 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
643 4,
644 minor,
645 (m_debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
647
648 if (context->initializeDrawingContext()) {
649 return context;
650 }
651 delete context;
652 }
653 return nullptr;
654 }
655#endif
656
657 case GHOST_kDrawingContextTypeD3D: {
658 GHOST_Context *context = new GHOST_ContextD3D(false, m_hWnd);
659
660 if (context->initializeDrawingContext()) {
661 return context;
662 }
663 delete context;
664 return nullptr;
665 }
666
667 default:
668 /* Unsupported backend. */
669 return nullptr;
670 }
671}
672
674{
675 if (m_hasMouseCaptured) {
676 m_hasGrabMouse = false;
677 m_nPressedButtons = 0;
678 m_hasMouseCaptured = false;
679 }
680}
681
683{
684 return m_isDialog;
685}
686
688{
689 switch (event) {
690 case MousePressed:
691 m_nPressedButtons++;
692 break;
693 case MouseReleased:
694 if (m_nPressedButtons) {
695 m_nPressedButtons--;
696 }
697 break;
698 case OperatorGrab:
699 m_hasGrabMouse = true;
700 break;
701 case OperatorUngrab:
702 m_hasGrabMouse = false;
703 break;
704 }
705
706 if (!m_nPressedButtons && !m_hasGrabMouse && m_hasMouseCaptured) {
707 ::ReleaseCapture();
708 m_hasMouseCaptured = false;
709 }
710 else if ((m_nPressedButtons || m_hasGrabMouse) && !m_hasMouseCaptured) {
711 ::SetCapture(m_hWnd);
712 m_hasMouseCaptured = true;
713 }
714}
715
717{
718 /* Convert GHOST cursor to Windows OEM cursor. */
719 HANDLE cursor = nullptr;
720 HMODULE module = ::GetModuleHandle(0);
721 uint32_t flags = LR_SHARED | LR_DEFAULTSIZE;
722 int cx = 0, cy = 0;
723
724 switch (shape) {
726 if (m_customCursor) {
727 return m_customCursor;
728 }
729 else {
730 return nullptr;
731 }
733 cursor = ::LoadImage(module, "arrowright_cursor", IMAGE_CURSOR, cx, cy, flags);
734 break;
736 cursor = ::LoadImage(module, "arrowleft_cursor", IMAGE_CURSOR, cx, cy, flags);
737 break;
739 cursor = ::LoadImage(module, "arrowup_cursor", IMAGE_CURSOR, cx, cy, flags);
740 break;
742 cursor = ::LoadImage(module, "arrowdown_cursor", IMAGE_CURSOR, cx, cy, flags);
743 break;
745 cursor = ::LoadImage(module, "splitv_cursor", IMAGE_CURSOR, cx, cy, flags);
746 break;
748 cursor = ::LoadImage(module, "splith_cursor", IMAGE_CURSOR, cx, cy, flags);
749 break;
751 cursor = ::LoadImage(module, "knife_cursor", IMAGE_CURSOR, cx, cy, flags);
752 break;
754 cursor = ::LoadImage(module, "eyedropper_cursor", IMAGE_CURSOR, cx, cy, flags);
755 break;
757 cursor = ::LoadImage(module, "zoomin_cursor", IMAGE_CURSOR, cx, cy, flags);
758 break;
760 cursor = ::LoadImage(module, "zoomout_cursor", IMAGE_CURSOR, cx, cy, flags);
761 break;
763 cursor = ::LoadImage(nullptr, IDC_SIZEALL, IMAGE_CURSOR, cx, cy, flags);
764 break;
766 cursor = ::LoadImage(module, "handopen_cursor", IMAGE_CURSOR, cx, cy, flags);
767 break;
769 cursor = ::LoadImage(module, "handclosed_cursor", IMAGE_CURSOR, cx, cy, flags);
770 break;
772 cursor = ::LoadImage(module, "handpoint_cursor", IMAGE_CURSOR, cx, cy, flags);
773 break;
775 cursor = ::LoadImage(module, "scrollnsew_cursor", IMAGE_CURSOR, cx, cy, flags);
776 break;
778 cursor = ::LoadImage(module, "scrollns_cursor", IMAGE_CURSOR, cx, cy, flags);
779 break;
781 cursor = ::LoadImage(module, "scrollew_cursor", IMAGE_CURSOR, cx, cy, flags);
782 break;
784 cursor = ::LoadImage(nullptr, IDC_HELP, IMAGE_CURSOR, cx, cy, flags);
785 break; /* Arrow and question mark */
787 cursor = ::LoadImage(nullptr, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags);
788 break; /* Hourglass */
790 cursor = ::LoadImage(nullptr, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags);
791 break; /* I-beam */
793 cursor = ::LoadImage(module, "cross_cursor", IMAGE_CURSOR, cx, cy, flags);
794 break; /* Standard Cross */
796 cursor = ::LoadImage(module, "crossA_cursor", IMAGE_CURSOR, cx, cy, flags);
797 break; /* Crosshair A */
799 cursor = ::LoadImage(module, "crossB_cursor", IMAGE_CURSOR, cx, cy, flags);
800 break; /* Diagonal Crosshair B */
802 cursor = ::LoadImage(module, "crossC_cursor", IMAGE_CURSOR, cx, cy, flags);
803 break; /* Minimal Crosshair C */
806 cursor = ::LoadImage(module, "movens_cursor", IMAGE_CURSOR, cx, cy, flags);
807 break; /* Double-pointed arrow pointing north and south */
810 cursor = ::LoadImage(module, "moveew_cursor", IMAGE_CURSOR, cx, cy, flags);
811 break; /* Double-pointed arrow pointing west and east */
813 cursor = ::LoadImage(nullptr, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags);
814 break; /* Vertical arrow */
816 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
817 break;
819 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
820 break;
822 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
823 break;
825 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
826 break;
828 cursor = ::LoadImage(module, "pencil_cursor", IMAGE_CURSOR, cx, cy, flags);
829 break;
831 cursor = ::LoadImage(module, "eraser_cursor", IMAGE_CURSOR, cx, cy, flags);
832 break;
835 cursor = ::LoadImage(module, "forbidden_cursor", IMAGE_CURSOR, cx, cy, flags);
836 break; /* Slashed circle */
838 cursor = ::LoadImage(module, "handle_left_cursor", IMAGE_CURSOR, cx, cy, flags);
839 break;
841 cursor = ::LoadImage(module, "handle_right_cursor", IMAGE_CURSOR, cx, cy, flags);
842 break;
844 cursor = ::LoadImage(module, "handle_both_cursor", IMAGE_CURSOR, cx, cy, flags);
845 break;
846
848 cursor = nullptr;
849 break;
850 default:
851 return nullptr;
852 }
853
854 if (cursor == nullptr) {
855 cursor = ::LoadImage(nullptr, IDC_ARROW, IMAGE_CURSOR, cx, cy, flags);
856 }
857
858 return (HCURSOR)cursor;
859}
860
862{
863 if (!visible) {
864 while (::ShowCursor(FALSE) >= 0) {
865 /* Pass. */
866 }
867 }
868 else {
869 while (::ShowCursor(TRUE) < 0) {
870 /* Pass. */
871 }
872 }
873
874 HCURSOR cursor = getStandardCursor(shape);
875 if (cursor == nullptr) {
877 }
878 ::SetCursor(cursor);
879}
880
881GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
882{
883 if (::GetForegroundWindow() == m_hWnd) {
884 loadCursor(visible, getCursorShape());
885 }
886
887 return GHOST_kSuccess;
888}
889
890GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
891{
892 if (mode != GHOST_kGrabDisable) {
893 if (mode != GHOST_kGrabNormal) {
894 m_system->getCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
895 setCursorGrabAccum(0, 0);
896
897 if (mode == GHOST_kGrabHide) {
898 setWindowCursorVisibility(false);
899 }
900 }
902 }
903 else {
905 m_system->setCursorPosition(m_cursorGrabInitPos[0], m_cursorGrabInitPos[1]);
906 setWindowCursorVisibility(true);
907 }
909 /* Use to generate a mouse move event, otherwise the last event
910 * blender gets can be outside the screen causing menus not to show
911 * properly unless the user moves the mouse. */
912 int32_t pos[2];
913 m_system->getCursorPosition(pos[0], pos[1]);
914 m_system->setCursorPosition(pos[0], pos[1]);
915 }
916
917 /* Almost works without but important otherwise the mouse GHOST location
918 * can be incorrect on exit. */
919 setCursorGrabAccum(0, 0);
920 m_cursorGrabBounds.m_l = m_cursorGrabBounds.m_r = -1; /* disable */
922 }
923
924 return GHOST_kSuccess;
925}
926
927GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursorShape)
928{
929 if (::GetForegroundWindow() == m_hWnd) {
930 loadCursor(getCursorVisibility(), cursorShape);
931 }
932
933 return GHOST_kSuccess;
934}
935
936GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorShape)
937{
938 return (getStandardCursor(cursorShape)) ? GHOST_kSuccess : GHOST_kFailure;
939}
940
942 std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM /*lParam*/)
943{
944 int32_t pointerId = GET_POINTERID_WPARAM(wParam);
945 int32_t isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
947 uint32_t outCount = 0;
948
949 if (!(GetPointerPenInfoHistory(pointerId, &outCount, nullptr))) {
950 return GHOST_kFailure;
951 }
952
953 std::vector<POINTER_PEN_INFO> pointerPenInfo(outCount);
954 outPointerInfo.resize(outCount);
955
956 if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
957 return GHOST_kFailure;
958 }
959
960 for (uint32_t i = 0; i < outCount; i++) {
961 POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo;
962 /* Obtain the basic information from the event. */
963 outPointerInfo[i].pointerId = pointerId;
964 outPointerInfo[i].isPrimary = isPrimary;
965
966 switch (pointerApiInfo.ButtonChangeType) {
967 case POINTER_CHANGE_FIRSTBUTTON_DOWN:
968 case POINTER_CHANGE_FIRSTBUTTON_UP:
969 outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft;
970 break;
971 case POINTER_CHANGE_SECONDBUTTON_DOWN:
972 case POINTER_CHANGE_SECONDBUTTON_UP:
973 outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight;
974 break;
975 case POINTER_CHANGE_THIRDBUTTON_DOWN:
976 case POINTER_CHANGE_THIRDBUTTON_UP:
977 outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle;
978 break;
979 case POINTER_CHANGE_FOURTHBUTTON_DOWN:
980 case POINTER_CHANGE_FOURTHBUTTON_UP:
981 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4;
982 break;
983 case POINTER_CHANGE_FIFTHBUTTON_DOWN:
984 case POINTER_CHANGE_FIFTHBUTTON_UP:
985 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5;
986 break;
987 default:
988 break;
989 }
990
991 outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation;
992 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus;
993 outPointerInfo[i].tabletData.Pressure = 1.0f;
994 outPointerInfo[i].tabletData.Xtilt = 0.0f;
995 outPointerInfo[i].tabletData.Ytilt = 0.0f;
996 outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount);
997
998 if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) {
999 outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f;
1000 }
1001
1002 if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) {
1003 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser;
1004 }
1005
1006 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) {
1007 /* Input value is a range of -90 to +90, with a positive value
1008 * indicating a tilt to the right. Convert to what Blender
1009 * expects: -1.0f (left) to +1.0f (right). */
1010 outPointerInfo[i].tabletData.Xtilt = std::clamp(
1011 pointerPenInfo[i].tiltX / 90.0f, -1.0f, 1.0f);
1012 }
1013
1014 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) {
1015 /* Input value is a range of -90 to +90, with a positive value
1016 * indicating a tilt toward the user. Convert to what Blender
1017 * expects: -1.0f (away from user) to +1.0f (toward user). */
1018 outPointerInfo[i].tabletData.Ytilt = std::clamp(
1019 pointerPenInfo[i].tiltY / 90.0f, -1.0f, 1.0f);
1020 }
1021 }
1022
1023 if (!outPointerInfo.empty()) {
1024 m_lastPointerTabletData = outPointerInfo.back().tabletData;
1025 }
1026
1027 return GHOST_kSuccess;
1028}
1029
1031{
1032 m_lastPointerTabletData = GHOST_TABLET_DATA_NONE;
1033}
1034
1036{
1037 return m_wintab;
1038}
1039
1041{
1042 if (!m_wintab) {
1043 WINTAB_PRINTF("Loading Wintab for window %p\n", m_hWnd);
1044 if (m_wintab = GHOST_Wintab::loadWintab(m_hWnd)) {
1045 if (enable) {
1046 m_wintab->enable();
1047
1048 /* Focus Wintab if cursor is inside this window. This ensures Wintab is enabled when the
1049 * tablet is used to change the Tablet API. */
1050 int32_t x, y;
1051 if (m_system->getCursorPosition(x, y)) {
1052 GHOST_Rect rect;
1053 getClientBounds(rect);
1054
1055 if (rect.isInside(x, y)) {
1056 m_wintab->gainFocus();
1057 }
1058 }
1059 }
1060 }
1061 }
1062}
1063
1065{
1066 WINTAB_PRINTF("Closing Wintab for window %p\n", m_hWnd);
1067 delete m_wintab;
1068 m_wintab = nullptr;
1069}
1070
1072{
1073 if (m_system->getTabletAPI() == api) {
1074 return true;
1075 }
1076 else if (m_system->getTabletAPI() == GHOST_kTabletAutomatic) {
1077 if (m_wintab && m_wintab->devicesPresent()) {
1078 return api == GHOST_kTabletWintab;
1079 }
1080 else {
1081 return api == GHOST_kTabletWinPointer;
1082 }
1083 }
1084 else {
1085 return false;
1086 }
1087}
1088
1090{
1092 return m_wintab ? m_wintab->getLastTabletData() : GHOST_TABLET_DATA_NONE;
1093 }
1094 else {
1095 return m_lastPointerTabletData;
1096 }
1097}
1098
1100{
1101 DWORD lightMode;
1102 DWORD pcbData = sizeof(lightMode);
1103 if (RegGetValueW(HKEY_CURRENT_USER,
1104 L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\",
1105 L"AppsUseLightTheme",
1106 RRF_RT_REG_DWORD,
1107 nullptr,
1108 &lightMode,
1109 &pcbData) == ERROR_SUCCESS)
1110 {
1111 BOOL DarkMode = !lightMode;
1112
1113 /* `20 == DWMWA_USE_IMMERSIVE_DARK_MODE` in Windows 11 SDK.
1114 * This value was undocumented for Windows 10 versions 2004 and later,
1115 * supported for Windows 11 Build 22000 and later. */
1116 DwmSetWindowAttribute(this->m_hWnd, 20, &DarkMode, sizeof(DarkMode));
1117 }
1118}
1119
1121{
1122 if (m_directManipulationHelper) {
1123 m_directManipulationHelper->setDPI(getDPIHint());
1124 }
1125}
1126
1128{
1129 if (m_user32) {
1130 GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow)::GetProcAddress(
1131 m_user32, "GetDpiForWindow");
1132
1133 if (fpGetDpiForWindow) {
1134 return fpGetDpiForWindow(this->m_hWnd);
1135 }
1136 }
1137
1138 return USER_DEFAULT_SCREEN_DPI;
1139}
1140
1142static uint8_t uns8ReverseBits(uint8_t ch)
1143{
1144 ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1145 ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1146 ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1147 return ch;
1148}
1149
1150#if 0 /* UNUSED */
1152static uint16_t uns16ReverseBits(uint16_t shrt)
1153{
1154 shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1155 shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1156 shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1157 shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1158 return shrt;
1159}
1160#endif
1161
1162GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(uint8_t *bitmap,
1163 uint8_t *mask,
1164 int sizeX,
1165 int sizeY,
1166 int hotX,
1167 int hotY,
1168 bool /*canInvertColor*/)
1169{
1170 uint32_t andData[32];
1171 uint32_t xorData[32];
1172 uint32_t fullBitRow, fullMaskRow;
1173 int x, y, cols;
1174
1175 cols = sizeX / 8; /* Number of whole bytes per row (width of bitmap/mask). */
1176 if (sizeX % 8) {
1177 cols++;
1178 }
1179
1180 if (m_customCursor) {
1181 DestroyCursor(m_customCursor);
1182 m_customCursor = nullptr;
1183 }
1184
1185 memset(&andData, 0xFF, sizeof(andData));
1186 memset(&xorData, 0, sizeof(xorData));
1187
1188 for (y = 0; y < sizeY; y++) {
1189 fullBitRow = 0;
1190 fullMaskRow = 0;
1191 for (x = cols - 1; x >= 0; x--) {
1192 fullBitRow <<= 8;
1193 fullMaskRow <<= 8;
1194 fullBitRow |= uns8ReverseBits(bitmap[cols * y + x]);
1195 fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1196 }
1197 xorData[y] = fullBitRow & fullMaskRow;
1198 andData[y] = ~fullMaskRow;
1199 }
1200
1201 m_customCursor = ::CreateCursor(::GetModuleHandle(0), hotX, hotY, 32, 32, andData, xorData);
1202 if (!m_customCursor) {
1203 return GHOST_kFailure;
1204 }
1205
1206 if (::GetForegroundWindow() == m_hWnd) {
1208 }
1209
1210 return GHOST_kSuccess;
1211}
1212
1214{
1215 /* #SetProgressValue sets state to #TBPF_NORMAL automatically. */
1216 if (m_Bar && S_OK == m_Bar->SetProgressValue(m_hWnd, 10000 * progress, 10000)) {
1217 return GHOST_kSuccess;
1218 }
1219
1220 return GHOST_kFailure;
1221}
1222
1224{
1225 if (m_Bar && S_OK == m_Bar->SetProgressState(m_hWnd, TBPF_NOPROGRESS)) {
1226 return GHOST_kSuccess;
1227 }
1228
1229 return GHOST_kFailure;
1230}
1231
1232#ifdef WITH_INPUT_IME
1233void GHOST_WindowWin32::beginIME(int32_t x, int32_t y, int32_t /*w*/, int32_t h, bool completed)
1234{
1235 m_imeInput.BeginIME(m_hWnd, GHOST_Rect(x, y - h, x, y), completed);
1236}
1237
1238void GHOST_WindowWin32::endIME()
1239{
1240 m_imeInput.EndIME(m_hWnd);
1241}
1242#endif /* WITH_INPUT_IME */
1243
1244void GHOST_WindowWin32::registerWindowAppUserModelProperties()
1245{
1246 IPropertyStore *pstore;
1247 char blender_path[MAX_PATH];
1248 wchar_t shell_command[MAX_PATH];
1249
1250 /* Find the current executable, and see if it's blender.exe if not bail out. */
1251 GetModuleFileName(0, blender_path, sizeof(blender_path));
1252 char *blender_app = strstr(blender_path, "blender.exe");
1253 if (!blender_app) {
1254 return;
1255 }
1256
1257 HRESULT hr = SHGetPropertyStoreForWindow(m_hWnd, IID_PPV_ARGS(&pstore));
1258 if (!SUCCEEDED(hr)) {
1259 return;
1260 }
1261
1262 /* Set the launcher as the shell command so the console window will not flash.
1263 * when people pin blender to the taskbar. */
1264 strcpy(blender_app, "blender-launcher.exe");
1265 wsprintfW(shell_command, L"\"%S\"", blender_path);
1266 UTF16_ENCODE(BLENDER_WIN_APPID);
1267 UTF16_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1268 PROPVARIANT propvar;
1269 hr = InitPropVariantFromString(BLENDER_WIN_APPID_16, &propvar);
1270 hr = pstore->SetValue(PKEY_AppUserModel_ID, propvar);
1271 hr = InitPropVariantFromString(shell_command, &propvar);
1272 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, propvar);
1273 hr = InitPropVariantFromString(BLENDER_WIN_APPID_FRIENDLY_NAME_16, &propvar);
1274 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, propvar);
1275 pstore->Release();
1276 UTF16_UN_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1277 UTF16_UN_ENCODE(BLENDER_WIN_APPID);
1278}
1279
1280/* as per MSDN: Any property not cleared before closing the window, will be leaked and NOT be
1281 * returned to the OS. */
1282void GHOST_WindowWin32::unregisterWindowAppUserModelProperties()
1283{
1284 IPropertyStore *pstore;
1285 HRESULT hr = SHGetPropertyStoreForWindow(m_hWnd, IID_PPV_ARGS(&pstore));
1286 if (SUCCEEDED(hr)) {
1287 PROPVARIANT value;
1288 PropVariantInit(&value);
1289 pstore->SetValue(PKEY_AppUserModel_ID, value);
1290 pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, value);
1291 pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, value);
1292 pstore->Release();
1293 }
1294}
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:80
@ GHOST_kFailure
Definition GHOST_Types.h:80
@ GHOST_kSuccess
Definition GHOST_Types.h:80
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
@ GHOST_kDecorationColoredTitleBar
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,...)
float progress
Definition WM_types.hh:1019
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
static GHOST_DirectManipulationHelper * create(HWND hWnd, uint16_t dpi)
static GHOST_ISystem * getSystem()
virtual bool isInside(int32_t x, int32_t y) const
virtual int32_t getHeight() const
virtual int32_t getWidth() const
uint64_t performanceCounterToMillis(__int64 perf_ticks) const
GHOST_TTabletAPI getTabletAPI()
GHOST_TSuccess invalidate()
GHOST_TSuccess setOrder(GHOST_TWindowOrder order)
uint16_t getDPIHint() override
GHOST_TTrackpadInfo getTrackpadInfo()
GHOST_TSuccess setProgressBar(float progress)
GHOST_TSuccess applyWindowDecorationStyle() override
void setTitle(const char *title)
std::string getTitle() 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, GHOST_WindowWin32 *parentWindow, bool is_debug, bool dialog, const GHOST_GPUDevice &preferred_device)
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
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_TWindowDecorationStyleFlags m_windowDecorationStyleFlags
GHOST_Rect m_cursorGrabBounds
GHOST_WindowDecorationStyleSettings m_windowDecorationStyleSettings
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 getValid() const override
bool getCursorVisibility() const override
GHOST_Window(uint32_t width, uint32_t height, GHOST_TWindowState state, const bool wantStereoVisual=false, const bool exclusive=false)
static GHOST_Wintab * loadWintab(HWND hwnd)
uint pos
uint top
#define long
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong state[N]
static int left
#define L
int context(const bContext *C, const char *member, bContextDataResult *result)
static struct PyModuleDef module
Definition python.cpp:796
#define min(a, b)
Definition sort.cc:36
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
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