Blender V5.0
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 const GHOST_ContextParams &context_params,
63 GHOST_WindowWin32 *parent_window,
64 bool dialog,
65 const GHOST_GPUDevice &preferred_device)
66 : GHOST_Window(width, height, state, context_params, false),
69 system_(system),
70 drop_target_(nullptr),
71 h_wnd_(0),
72 h_DC_(0),
73 is_dialog_(dialog),
74 preferred_device_(preferred_device),
75 has_mouse_captured_(false),
76 has_grab_mouse_(false),
77 n_pressed_buttons_(0),
78 custom_cursor_(0),
79 bar_(nullptr),
80 wintab_(nullptr),
81 last_pointer_tablet_data_(GHOST_TABLET_DATA_NONE),
82 normal_state_(GHOST_kWindowStateNormal),
83 user32_(::LoadLibrary("user32.dll")),
84 parent_window_hwnd_(parent_window ? parent_window->h_wnd_ : HWND_DESKTOP),
85 direct_manipulation_helper_(nullptr)
86{
87 DWORD style = parent_window ?
88 WS_POPUPWINDOW | WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SIZEBOX :
89 WS_OVERLAPPEDWINDOW;
90
92 style |= WS_MAXIMIZE;
93 }
94
95 /* Forces owned windows onto taskbar and allows minimization. */
96 DWORD extended_style = parent_window ? WS_EX_APPWINDOW : 0;
97
98 if (dialog) {
99 /* When we are ready to make windows of this type:
100 * style = WS_POPUPWINDOW | WS_CAPTION
101 * extended_style = WS_EX_DLGMODALFRAME | WS_EX_TOPMOST
102 */
103 }
104
105 RECT win_rect = {left, top, long(left + width), long(top + height)};
106 adjustWindowRectForClosestMonitor(&win_rect, style, extended_style);
107
108 wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
109 h_wnd_ = ::CreateWindowExW(extended_style, /* window extended style */
110 s_windowClassName, /* pointer to registered class name */
111 title_16, /* pointer to window name */
112 style, /* window style */
113 win_rect.left, /* horizontal position of window */
114 win_rect.top, /* vertical position of window */
115 win_rect.right - win_rect.left, /* window width */
116 win_rect.bottom - win_rect.top, /* window height */
117 parent_window_hwnd_, /* handle to parent or owner window */
118 0, /* handle to menu or child-window identifier */
119 ::GetModuleHandle(0), /* handle to application instance */
120 0); /* pointer to window-creation data */
121 free(title_16);
122
123 if (h_wnd_ == nullptr) {
124 return;
125 }
126
127 registerWindowAppUserModelProperties();
128
129 /* Store the device context. */
130 h_DC_ = ::GetDC(h_wnd_);
131
132 if (!setDrawingContextType(type)) {
133 const char *title = "Blender - Unsupported Graphics Card Configuration";
134 const char *text = "";
135#if defined(WIN32)
136 if (strncmp(BLI_getenv("PROCESSOR_IDENTIFIER"), "ARM", 3) == 0 &&
137 strstr(BLI_getenv("PROCESSOR_IDENTIFIER"), "Qualcomm") != NULL)
138 {
139 text =
140 "A driver with support for OpenGL 4.3 or higher is required.\n\n"
141 "Qualcomm devices require the \"OpenCL™, OpenGL®, and Vulkan® Compatibility Pack\" "
142 "from the Microsoft Store.\n\n"
143 "Devices using processors older than a Qualcomm Snapdragon 8cx Gen3 are incompatible, "
144 "but may be able to run an emulated x64 copy of Blender, such as a 3.x LTS release.";
145 }
146 else
147#endif
148 {
149 text =
150 "A graphics card and driver with support for OpenGL 4.3 or higher is "
151 "required.\n\nInstalling the latest driver for your graphics card might resolve the "
152 "issue.";
153 if (GetSystemMetrics(SM_CMONITORS) > 1) {
154 text =
155 "A graphics card and driver with support for OpenGL 4.3 or higher is "
156 "required.\n\nPlugging all monitors into your primary graphics card might resolve "
157 "this issue. Installing the latest driver for your graphics card could also help.";
158 }
159 }
160 MessageBox(h_wnd_, text, title, MB_OK | MB_ICONERROR);
161 ::ReleaseDC(h_wnd_, h_DC_);
162 ::DestroyWindow(h_wnd_);
163 h_wnd_ = nullptr;
164 if (!parent_window) {
165 exit(0);
166 }
167 return;
168 }
169
170 RegisterTouchWindow(h_wnd_, 0);
171
172 /* Register as drop-target. #OleInitialize(0) required first, done in GHOST_SystemWin32. */
173 drop_target_ = new GHOST_DropTargetWin32(this, system_);
174 ::RegisterDragDrop(h_wnd_, drop_target_);
175
176 /* Store a pointer to this class in the window structure. */
177 ::SetWindowLongPtr(h_wnd_, GWLP_USERDATA, (LONG_PTR)this);
178
179 if (!system_->window_focus_) {
180 /* If we don't want focus then lower to bottom. */
181 ::SetWindowPos(h_wnd_, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
182 }
183
184 if (parent_window) {
185 /* Release any parent capture to allow immediate interaction (#90110). */
186 ::ReleaseCapture();
187 parent_window->lostMouseCapture();
188 }
189
190 /* Show the window. */
191 int nCmdShow;
192 switch (state) {
195 nCmdShow = SW_SHOWMAXIMIZED;
196 break;
198 nCmdShow = (system_->window_focus_) ? SW_SHOWMINIMIZED : SW_SHOWMINNOACTIVE;
199 break;
201 default:
202 nCmdShow = (system_->window_focus_) ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
203 break;
204 }
205
206 ThemeRefresh();
207
208 ::ShowWindow(h_wnd_, nCmdShow);
209
210 /* Initialize WINTAB. */
211 if (system->getTabletAPI() != GHOST_kTabletWinPointer) {
213 }
214
215 /* Allow the showing of a progress bar on the taskbar. */
216 CoCreateInstance(
217 CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&bar_);
218
219 /* Initialize Direct Manipulation. */
220 direct_manipulation_helper_ = GHOST_DirectManipulationHelper::create(h_wnd_, getDPIHint());
221
222 /* Initialize HDR info. */
224}
225
227{
228 if (!direct_manipulation_helper_) {
229 return;
230 }
231
232 direct_manipulation_helper_->update();
233}
234
236{
237 /* Only #DM_POINTERHITTEST can be the first message of input sequence of touch-pad input. */
238
239 if (!direct_manipulation_helper_) {
240 return;
241 }
242
243 UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
244 POINTER_INPUT_TYPE pointerType;
245 if (GetPointerType(pointerId, &pointerType) && pointerType == PT_TOUCHPAD) {
246 direct_manipulation_helper_->onPointerHitTest(pointerId);
247 }
248}
249
251{
252 if (!direct_manipulation_helper_) {
253 return {0, 0, 0};
254 }
255
256 return direct_manipulation_helper_->getTrackpadInfo();
257}
258
260{
261 if (h_wnd_) {
262 unregisterWindowAppUserModelProperties();
263 }
264
265 if (bar_) {
266 bar_->SetProgressState(h_wnd_, TBPF_NOPROGRESS);
267 bar_->Release();
268 bar_ = nullptr;
269 }
270
271 closeWintab();
272
273 if (user32_) {
274 FreeLibrary(user32_);
275 user32_ = nullptr;
276 }
277
278 if (custom_cursor_) {
279 DestroyCursor(custom_cursor_);
280 custom_cursor_ = nullptr;
281 }
282
283 if (h_wnd_ != nullptr && h_DC_ != nullptr && releaseNativeHandles()) {
284 ::ReleaseDC(h_wnd_, h_DC_);
285 h_DC_ = nullptr;
286 }
287
288 if (h_wnd_) {
289 /* If this window is referenced by others as parent, clear that relation or windows will free
290 * the handle while we still reference it. */
291 for (GHOST_IWindow *iter_win : system_->getWindowManager()->getWindows()) {
292 GHOST_WindowWin32 *iter_winwin = (GHOST_WindowWin32 *)iter_win;
293 if (iter_winwin->parent_window_hwnd_ == h_wnd_) {
294 ::SetWindowLongPtr(iter_winwin->h_wnd_, GWLP_HWNDPARENT, 0);
295 iter_winwin->parent_window_hwnd_ = 0;
296 }
297 }
298
299 if (drop_target_) {
300 /* Disable DragDrop. */
301 RevokeDragDrop(h_wnd_);
302 /* Release our reference of the DropTarget and it will delete itself eventually. */
303 drop_target_->Release();
304 drop_target_ = nullptr;
305 }
306 ::SetWindowLongPtr(h_wnd_, GWLP_USERDATA, 0);
307 ::DestroyWindow(h_wnd_);
308 h_wnd_ = 0;
309 }
310
311 delete direct_manipulation_helper_;
312 direct_manipulation_helper_ = nullptr;
313}
314
316 DWORD dwStyle,
317 DWORD dwExStyle)
318{
319 /* Get Details of the closest monitor. */
320 HMONITOR hmonitor = MonitorFromRect(win_rect, MONITOR_DEFAULTTONEAREST);
321 MONITORINFOEX monitor;
322 monitor.cbSize = sizeof(MONITORINFOEX);
323 monitor.dwFlags = 0;
324 GetMonitorInfo(hmonitor, &monitor);
325
326 /* Constrain requested size and position to fit within this monitor. */
327 LONG width = min(monitor.rcWork.right - monitor.rcWork.left, win_rect->right - win_rect->left);
328 LONG height = min(monitor.rcWork.bottom - monitor.rcWork.top, win_rect->bottom - win_rect->top);
329 win_rect->left = min(max(monitor.rcWork.left, win_rect->left), monitor.rcWork.right - width);
330 win_rect->right = win_rect->left + width;
331 win_rect->top = min(max(monitor.rcWork.top, win_rect->top), monitor.rcWork.bottom - height);
332 win_rect->bottom = win_rect->top + height;
333
334 /* With Windows 10 and newer we can adjust for chrome that differs with DPI and scale. */
335 GHOST_WIN32_AdjustWindowRectExForDpi fpAdjustWindowRectExForDpi = nullptr;
336 if (user32_) {
337 fpAdjustWindowRectExForDpi = (GHOST_WIN32_AdjustWindowRectExForDpi)::GetProcAddress(
338 user32_, "AdjustWindowRectExForDpi");
339 }
340
341 /* Adjust to allow for caption, borders, shadows, scaling, etc. Resulting values can be
342 * correctly outside of monitor bounds. NOTE: You cannot specify #WS_OVERLAPPED when calling. */
343 if (fpAdjustWindowRectExForDpi) {
344 UINT dpiX, dpiY;
345 GetDpiForMonitor(hmonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
346 fpAdjustWindowRectExForDpi(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle, dpiX);
347 }
348 else {
349 AdjustWindowRectEx(win_rect, dwStyle & ~WS_OVERLAPPED, FALSE, dwExStyle);
350 }
351
352 /* But never allow a top position that can hide part of the title bar. */
353 win_rect->top = max(monitor.rcWork.top, win_rect->top);
354}
355
357{
358 return GHOST_Window::getValid() && h_wnd_ != 0 && h_DC_ != 0;
359}
360
362{
363 return h_wnd_;
364}
365
367{
368 return (void *)h_wnd_;
369}
370
371void GHOST_WindowWin32::setTitle(const char *title)
372{
373 wchar_t *title_16 = alloc_utf16_from_8((char *)title, 0);
374 ::SetWindowTextW(h_wnd_, (wchar_t *)title_16);
375 free(title_16);
376}
377
379{
380 std::wstring wtitle(::GetWindowTextLengthW(h_wnd_) + 1, L'\0');
381 ::GetWindowTextW(h_wnd_, &wtitle[0], wtitle.capacity());
382
383 std::string title(count_utf_8_from_16(wtitle.c_str()) + 1, '\0');
384 conv_utf_16_to_8(wtitle.c_str(), &title[0], title.capacity());
385
386 return title;
387}
388
390{
391 /* DWMWINDOWATTRIBUTE::DWMWA_CAPTION_COLOR */
392 constexpr DWORD caption_color_attr = 35;
393
395 const float *color = window_decoration_style_settings_.colored_titlebar_bg_color;
396 const COLORREF colorref = RGB(
397 char(color[0] * 255.0f), char(color[1] * 255.0f), char(color[2] * 255.0f));
398 if (!SUCCEEDED(DwmSetWindowAttribute(h_wnd_, caption_color_attr, &colorref, sizeof(colorref))))
399 {
400 return GHOST_kFailure;
401 }
402 }
403 return GHOST_kSuccess;
404}
405
407{
408 RECT rect;
409 ::GetWindowRect(h_wnd_, &rect);
410 bounds.b_ = rect.bottom;
411 bounds.l_ = rect.left;
412 bounds.r_ = rect.right;
413 bounds.t_ = rect.top;
414}
415
417{
418 RECT rect;
419 POINT coord;
420 if (!IsIconic(h_wnd_)) {
421 ::GetClientRect(h_wnd_, &rect);
422
423 coord.x = rect.left;
424 coord.y = rect.top;
425 ::ClientToScreen(h_wnd_, &coord);
426
427 bounds.l_ = coord.x;
428 bounds.t_ = coord.y;
429
430 coord.x = rect.right;
431 coord.y = rect.bottom;
432 ::ClientToScreen(h_wnd_, &coord);
433
434 bounds.r_ = coord.x;
435 bounds.b_ = coord.y;
436 }
437 else {
438 bounds.b_ = 0;
439 bounds.l_ = 0;
440 bounds.r_ = 0;
441 bounds.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(h_wnd_, 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(h_wnd_, HWND_TOP, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER) ?
476 }
477 else {
478 success = GHOST_kSuccess;
479 }
480 return success;
481}
482
483GHOST_TSuccess GHOST_WindowWin32::setClientSize(uint32_t width, uint32_t height)
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(h_wnd_, 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(h_wnd_)) {
506 }
507 else if (::IsZoomed(h_wnd_)) {
508 LONG_PTR result = ::GetWindowLongPtr(h_wnd_, GWL_STYLE);
510 }
512}
513
515 int32_t inY,
516 int32_t &outX,
517 int32_t &outY) const
518{
519 POINT point = {inX, inY};
520 ::ScreenToClient(h_wnd_, &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(h_wnd_, &point);
532 outX = point.x;
533 outY = point.y;
534}
535
537{
538 GHOST_TWindowState curstate = getState();
539 LONG_PTR style = GetWindowLongPtr(h_wnd_, GWL_STYLE) | WS_CAPTION;
540 WINDOWPLACEMENT wp;
541 wp.length = sizeof(WINDOWPLACEMENT);
542 ::GetWindowPlacement(h_wnd_, &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 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 && normal_state_ == GHOST_kWindowStateMaximized)
563 {
564 wp.showCmd = SW_SHOWMAXIMIZED;
565 normal_state_ = GHOST_kWindowStateNormal;
566 }
567 else {
568 wp.showCmd = SW_SHOWNORMAL;
569 }
570 break;
571 }
572 ::SetWindowLongPtr(h_wnd_, GWL_STYLE, style);
573 /* #SetWindowLongPtr Docs:
574 * Frame changes not visible until #SetWindowPos with #SWP_FRAMECHANGED. */
575 ::SetWindowPos(h_wnd_, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
576 return ::SetWindowPlacement(h_wnd_, &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(h_wnd_, GW_HWNDNEXT); /* the window to raise */
586 }
587 else {
590 }
591 hWndInsertAfter = HWND_TOP;
592 hWndToRaise = nullptr;
593 }
594
595 if (::SetWindowPos(h_wnd_, 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 (h_wnd_) {
611 success = ::InvalidateRect(h_wnd_, 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 want_context_params_, h_wnd_, 1, 2, preferred_device_, &hdr_info_);
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 h_wnd_,
641 h_DC_,
642 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
643 4,
644 minor,
645 (want_context_params_.is_debug ? 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(want_context_params_, h_wnd_);
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 (has_mouse_captured_) {
676 has_grab_mouse_ = false;
677 n_pressed_buttons_ = 0;
678 has_mouse_captured_ = false;
679 }
680}
681
683{
684 return is_dialog_;
685}
686
688{
689 switch (event) {
690 case MousePressed:
691 n_pressed_buttons_++;
692 break;
693 case MouseReleased:
694 if (n_pressed_buttons_) {
695 n_pressed_buttons_--;
696 }
697 break;
698 case OperatorGrab:
699 has_grab_mouse_ = true;
700 break;
701 case OperatorUngrab:
702 has_grab_mouse_ = false;
703 break;
704 }
705
706 if (!n_pressed_buttons_ && !has_grab_mouse_ && has_mouse_captured_) {
707 ::ReleaseCapture();
708 has_mouse_captured_ = false;
709 }
710 else if ((n_pressed_buttons_ || has_grab_mouse_) && !has_mouse_captured_) {
711 ::SetCapture(h_wnd_);
712 has_mouse_captured_ = true;
713 }
714}
715
717{
718 /* Convert GHOST cursor to Windows OEM cursor. */
719 HANDLE cursor = nullptr;
720 uint32_t flags = LR_SHARED | LR_DEFAULTSIZE;
721 int cx = 0, cy = 0;
722
723 switch (shape) {
725 if (custom_cursor_) {
726 return custom_cursor_;
727 }
728 else {
729 return nullptr;
730 }
732 cursor = ::LoadImage(nullptr, IDC_SIZEALL, IMAGE_CURSOR, cx, cy, flags);
733 break;
735 cursor = ::LoadImage(nullptr, IDC_HELP, IMAGE_CURSOR, cx, cy, flags);
736 break; /* Arrow and question mark */
738 cursor = ::LoadImage(nullptr, IDC_WAIT, IMAGE_CURSOR, cx, cy, flags);
739 break; /* Hourglass */
741 cursor = ::LoadImage(nullptr, IDC_IBEAM, IMAGE_CURSOR, cx, cy, flags);
742 break; /* I-beam */
744 cursor = ::LoadImage(nullptr, IDC_UPARROW, IMAGE_CURSOR, cx, cy, flags);
745 break; /* Vertical arrow */
747 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
748 break;
750 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
751 break;
753 cursor = ::LoadImage(nullptr, IDC_SIZENWSE, IMAGE_CURSOR, cx, cy, flags);
754 break;
756 cursor = ::LoadImage(nullptr, IDC_SIZENESW, IMAGE_CURSOR, cx, cy, flags);
757 break;
759 cursor = nullptr;
760 break;
761 default:
762 return nullptr;
763 }
764
765 if (cursor == nullptr) {
766 cursor = ::LoadImage(nullptr, IDC_ARROW, IMAGE_CURSOR, cx, cy, flags);
767 }
768
769 return (HCURSOR)cursor;
770}
771
773{
774 if (!visible) {
775 while (::ShowCursor(FALSE) >= 0) {
776 /* Pass. */
777 }
778 }
779 else {
780 while (::ShowCursor(TRUE) < 0) {
781 /* Pass. */
782 }
783 }
784
785 HCURSOR cursor = getStandardCursor(shape);
786 if (cursor == nullptr) {
788 }
789 ::SetCursor(cursor);
790}
791
792GHOST_TSuccess GHOST_WindowWin32::setWindowCursorVisibility(bool visible)
793{
794 if (::GetForegroundWindow() == h_wnd_) {
795 loadCursor(visible, getCursorShape());
796 }
797
798 return GHOST_kSuccess;
799}
800
801GHOST_TSuccess GHOST_WindowWin32::setWindowCursorGrab(GHOST_TGrabCursorMode mode)
802{
803 if (mode != GHOST_kGrabDisable) {
804 if (mode != GHOST_kGrabNormal) {
805 system_->getCursorPosition(cursor_grab_init_pos_[0], cursor_grab_init_pos_[1]);
806 setCursorGrabAccum(0, 0);
807
808 if (mode == GHOST_kGrabHide) {
809 setWindowCursorVisibility(false);
810 }
811 }
813 }
814 else {
816 system_->setCursorPosition(cursor_grab_init_pos_[0], cursor_grab_init_pos_[1]);
817 setWindowCursorVisibility(true);
818 }
820 /* Use to generate a mouse move event, otherwise the last event
821 * blender gets can be outside the screen causing menus not to show
822 * properly unless the user moves the mouse. */
823 int32_t pos[2];
824 system_->getCursorPosition(pos[0], pos[1]);
825 system_->setCursorPosition(pos[0], pos[1]);
826 }
827
828 /* Almost works without but important otherwise the mouse GHOST location
829 * can be incorrect on exit. */
830 setCursorGrabAccum(0, 0);
831 cursor_grab_bounds_.l_ = cursor_grab_bounds_.r_ = -1; /* disable */
833 }
834
835 return GHOST_kSuccess;
836}
837
838GHOST_TSuccess GHOST_WindowWin32::setWindowCursorShape(GHOST_TStandardCursor cursor_shape)
839{
840 if (::GetForegroundWindow() == h_wnd_) {
841 loadCursor(getCursorVisibility(), cursor_shape);
842 }
843
844 return GHOST_kSuccess;
845}
846
847GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursor_shape)
848{
849 return (getStandardCursor(cursor_shape)) ? GHOST_kSuccess : GHOST_kFailure;
850}
851
853 std::vector<GHOST_PointerInfoWin32> &outPointerInfo, WPARAM wParam, LPARAM /*lParam*/)
854{
855 int32_t pointerId = GET_POINTERID_WPARAM(wParam);
856 int32_t isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam);
858 uint32_t outCount = 0;
859
860 if (!(GetPointerPenInfoHistory(pointerId, &outCount, nullptr))) {
861 return GHOST_kFailure;
862 }
863
864 std::vector<POINTER_PEN_INFO> pointerPenInfo(outCount);
865 outPointerInfo.resize(outCount);
866
867 if (!(GetPointerPenInfoHistory(pointerId, &outCount, pointerPenInfo.data()))) {
868 return GHOST_kFailure;
869 }
870
871 for (uint32_t i = 0; i < outCount; i++) {
872 POINTER_INFO pointerApiInfo = pointerPenInfo[i].pointerInfo;
873 /* Obtain the basic information from the event. */
874 outPointerInfo[i].pointerId = pointerId;
875 outPointerInfo[i].isPrimary = isPrimary;
876
877 switch (pointerApiInfo.ButtonChangeType) {
878 case POINTER_CHANGE_FIRSTBUTTON_DOWN:
879 case POINTER_CHANGE_FIRSTBUTTON_UP:
880 outPointerInfo[i].buttonMask = GHOST_kButtonMaskLeft;
881 break;
882 case POINTER_CHANGE_SECONDBUTTON_DOWN:
883 case POINTER_CHANGE_SECONDBUTTON_UP:
884 outPointerInfo[i].buttonMask = GHOST_kButtonMaskRight;
885 break;
886 case POINTER_CHANGE_THIRDBUTTON_DOWN:
887 case POINTER_CHANGE_THIRDBUTTON_UP:
888 outPointerInfo[i].buttonMask = GHOST_kButtonMaskMiddle;
889 break;
890 case POINTER_CHANGE_FOURTHBUTTON_DOWN:
891 case POINTER_CHANGE_FOURTHBUTTON_UP:
892 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton4;
893 break;
894 case POINTER_CHANGE_FIFTHBUTTON_DOWN:
895 case POINTER_CHANGE_FIFTHBUTTON_UP:
896 outPointerInfo[i].buttonMask = GHOST_kButtonMaskButton5;
897 break;
898 default:
899 break;
900 }
901
902 outPointerInfo[i].pixelLocation = pointerApiInfo.ptPixelLocation;
903 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeStylus;
904 outPointerInfo[i].tabletData.Pressure = 1.0f;
905 outPointerInfo[i].tabletData.Xtilt = 0.0f;
906 outPointerInfo[i].tabletData.Ytilt = 0.0f;
907 outPointerInfo[i].time = system->performanceCounterToMillis(pointerApiInfo.PerformanceCount);
908
909 if (pointerPenInfo[i].penMask & PEN_MASK_PRESSURE) {
910 outPointerInfo[i].tabletData.Pressure = pointerPenInfo[i].pressure / 1024.0f;
911 }
912
913 if (pointerPenInfo[i].penFlags & PEN_FLAG_ERASER) {
914 outPointerInfo[i].tabletData.Active = GHOST_kTabletModeEraser;
915 }
916
917 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_X) {
918 /* Input value is a range of -90 to +90, with a positive value
919 * indicating a tilt to the right. Convert to what Blender
920 * expects: -1.0f (left) to +1.0f (right). */
921 outPointerInfo[i].tabletData.Xtilt = std::clamp(
922 pointerPenInfo[i].tiltX / 90.0f, -1.0f, 1.0f);
923 }
924
925 if (pointerPenInfo[i].penMask & PEN_MASK_TILT_Y) {
926 /* Input value is a range of -90 to +90, with a positive value
927 * indicating a tilt toward the user. Convert to what Blender
928 * expects: -1.0f (away from user) to +1.0f (toward user). */
929 outPointerInfo[i].tabletData.Ytilt = std::clamp(
930 pointerPenInfo[i].tiltY / 90.0f, -1.0f, 1.0f);
931 }
932 }
933
934 if (!outPointerInfo.empty()) {
935 last_pointer_tablet_data_ = outPointerInfo.back().tabletData;
936 }
937
938 return GHOST_kSuccess;
939}
940
942{
943 last_pointer_tablet_data_ = GHOST_TABLET_DATA_NONE;
944}
945
947{
948 return wintab_;
949}
950
952{
953 if (!wintab_) {
954 WINTAB_PRINTF("Loading Wintab for window %p\n", h_wnd_);
955 if (wintab_ = GHOST_Wintab::loadWintab(h_wnd_)) {
956 if (enable) {
957 wintab_->enable();
958
959 /* Focus Wintab if cursor is inside this window. This ensures Wintab is enabled when the
960 * tablet is used to change the Tablet API. */
961 int32_t x, y;
962 if (system_->getCursorPosition(x, y)) {
963 GHOST_Rect rect;
964 getClientBounds(rect);
965
966 if (rect.isInside(x, y)) {
967 wintab_->gainFocus();
968 }
969 }
970 }
971 }
972 }
973}
974
976{
977 WINTAB_PRINTF("Closing Wintab for window %p\n", h_wnd_);
978 delete wintab_;
979 wintab_ = nullptr;
980}
981
983{
984 if (system_->getTabletAPI() == api) {
985 return true;
986 }
987 else if (system_->getTabletAPI() == GHOST_kTabletAutomatic) {
988 if (wintab_ && wintab_->devicesPresent()) {
989 return api == GHOST_kTabletWintab;
990 }
991 else {
992 return api == GHOST_kTabletWinPointer;
993 }
994 }
995 else {
996 return false;
997 }
998}
999
1001{
1003 return wintab_ ? wintab_->getLastTabletData() : GHOST_TABLET_DATA_NONE;
1004 }
1005 else {
1006 return last_pointer_tablet_data_;
1007 }
1008}
1009
1011{
1012 DWORD lightMode;
1013 DWORD pcbData = sizeof(lightMode);
1014 if (RegGetValueW(HKEY_CURRENT_USER,
1015 L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize\\",
1016 L"AppsUseLightTheme",
1017 RRF_RT_REG_DWORD,
1018 nullptr,
1019 &lightMode,
1020 &pcbData) == ERROR_SUCCESS)
1021 {
1022 BOOL DarkMode = !lightMode;
1023
1024 /* `20 == DWMWA_USE_IMMERSIVE_DARK_MODE` in Windows 11 SDK.
1025 * This value was undocumented for Windows 10 versions 2004 and later,
1026 * supported for Windows 11 Build 22000 and later. */
1027 DwmSetWindowAttribute(this->h_wnd_, 20, &DarkMode, sizeof(DarkMode));
1028 }
1029}
1030
1032{
1033 if (direct_manipulation_helper_) {
1034 direct_manipulation_helper_->setDPI(getDPIHint());
1035 }
1036}
1037
1039{
1040 if (user32_) {
1041 GHOST_WIN32_GetDpiForWindow fpGetDpiForWindow = (GHOST_WIN32_GetDpiForWindow)::GetProcAddress(
1042 user32_, "GetDpiForWindow");
1043
1044 if (fpGetDpiForWindow) {
1045 return fpGetDpiForWindow(this->h_wnd_);
1046 }
1047 }
1048
1049 return USER_DEFAULT_SCREEN_DPI;
1050}
1051
1053static uint8_t uns8ReverseBits(uint8_t ch)
1054{
1055 ch = ((ch >> 1) & 0x55) | ((ch << 1) & 0xAA);
1056 ch = ((ch >> 2) & 0x33) | ((ch << 2) & 0xCC);
1057 ch = ((ch >> 4) & 0x0F) | ((ch << 4) & 0xF0);
1058 return ch;
1059}
1060
1061#if 0 /* UNUSED */
1063static uint16_t uns16ReverseBits(uint16_t shrt)
1064{
1065 shrt = ((shrt >> 1) & 0x5555) | ((shrt << 1) & 0xAAAA);
1066 shrt = ((shrt >> 2) & 0x3333) | ((shrt << 2) & 0xCCCC);
1067 shrt = ((shrt >> 4) & 0x0F0F) | ((shrt << 4) & 0xF0F0);
1068 shrt = ((shrt >> 8) & 0x00FF) | ((shrt << 8) & 0xFF00);
1069 return shrt;
1070}
1071#endif
1072
1073GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(const uint8_t *bitmap,
1074 const uint8_t *mask,
1075 const int size[2],
1076 const int hot_spot[2],
1077 bool /*can_invert_color*/)
1078{
1079 if (mask) {
1080 /* Old 1bpp XBitMap bitmap and mask. */
1081 uint32_t andData[32];
1082 uint32_t xorData[32];
1083 uint32_t fullBitRow, fullMaskRow;
1084 int x, y, cols;
1085
1086 cols = size[0] / 8; /* Number of whole bytes per row (width of bitmap/mask). */
1087 if (size[0] % 8) {
1088 cols++;
1089 }
1090
1091 HCURSOR previous_cursor = custom_cursor_;
1092
1093 memset(&andData, 0xFF, sizeof(andData));
1094 memset(&xorData, 0, sizeof(xorData));
1095
1096 for (y = 0; y < size[1]; y++) {
1097 fullBitRow = 0;
1098 fullMaskRow = 0;
1099 for (x = cols - 1; x >= 0; x--) {
1100 fullBitRow <<= 8;
1101 fullMaskRow <<= 8;
1102 fullBitRow |= uns8ReverseBits(bitmap[cols * y + x]);
1103 fullMaskRow |= uns8ReverseBits(mask[cols * y + x]);
1104 }
1105 xorData[y] = fullBitRow & fullMaskRow;
1106 andData[y] = ~fullMaskRow;
1107 }
1108
1109 custom_cursor_ = ::CreateCursor(
1110 ::GetModuleHandle(0), hot_spot[0], hot_spot[1], 32, 32, andData, xorData);
1111
1112 if (!custom_cursor_) {
1113 return GHOST_kFailure;
1114 }
1115
1116 if (::GetForegroundWindow() == h_wnd_) {
1118 }
1119
1120 if (previous_cursor) {
1121 DestroyCursor(previous_cursor);
1122 }
1123
1124 return GHOST_kSuccess;
1125 }
1126
1127 /* RGBA bitmap, size up to 255x255. This limit may differ on other
1128 * platforms. Requesting larger does not give an error, just results
1129 * in a smaller, empty result. */
1130
1131 BITMAPV5HEADER header;
1132 memset(&header, 0, sizeof(BITMAPV5HEADER));
1133 header.bV5Size = sizeof(BITMAPV5HEADER);
1134 header.bV5Width = (LONG)size[0];
1135 header.bV5Height = (LONG)size[1];
1136 header.bV5Planes = 1;
1137 header.bV5BitCount = 32;
1138 header.bV5Compression = BI_BITFIELDS;
1139 header.bV5RedMask = 0x00FF0000;
1140 header.bV5GreenMask = 0x0000FF00;
1141 header.bV5BlueMask = 0x000000FF;
1142 header.bV5AlphaMask = 0xFF000000;
1143
1144 HDC hdc = GetDC(h_wnd_);
1145 void *bits = nullptr;
1146 HBITMAP bmp = CreateDIBSection(
1147 hdc, (BITMAPINFO *)&header, DIB_RGB_COLORS, (void **)&bits, NULL, (DWORD)0);
1148 ReleaseDC(NULL, hdc);
1149
1150 uint32_t *ptr = (uint32_t *)bits;
1151 char w = size[0];
1152 char h = size[1];
1153 for (int y = h - 1; y >= 0; y--) {
1154 for (int x = 0; x < w; x++) {
1155 int i = (y * w * 4) + (x * 4);
1156 uint32_t r = bitmap[i];
1157 uint32_t g = bitmap[i + 1];
1158 uint32_t b = bitmap[i + 2];
1159 uint32_t a = bitmap[i + 3];
1160 *ptr++ = (a << 24) | (r << 16) | (g << 8) | b;
1161 }
1162 }
1163
1164 HBITMAP empty_mask = CreateBitmap(size[0], size[1], 1, 1, NULL);
1165 ICONINFO icon_info;
1166 icon_info.fIcon = FALSE;
1167 icon_info.xHotspot = (DWORD)hot_spot[0];
1168 icon_info.yHotspot = (DWORD)hot_spot[1];
1169 icon_info.hbmMask = empty_mask;
1170 icon_info.hbmColor = bmp;
1171
1172 HCURSOR previous_cursor = custom_cursor_;
1173
1174 custom_cursor_ = CreateIconIndirect(&icon_info);
1175 DeleteObject(bmp);
1176 DeleteObject(empty_mask);
1177
1178 if (!custom_cursor_) {
1179 return GHOST_kFailure;
1180 }
1181
1182 if (::GetForegroundWindow() == h_wnd_) {
1184 }
1185
1186 if (previous_cursor) {
1187 DestroyCursor(previous_cursor);
1188 }
1189
1190 return GHOST_kSuccess;
1191}
1192
1194{
1195 /* #SetProgressValue sets state to #TBPF_NORMAL automatically. */
1196 if (bar_ && S_OK == bar_->SetProgressValue(h_wnd_, 10000 * progress, 10000)) {
1197 return GHOST_kSuccess;
1198 }
1199
1200 return GHOST_kFailure;
1201}
1202
1204{
1205 if (bar_ && S_OK == bar_->SetProgressState(h_wnd_, TBPF_NOPROGRESS)) {
1206 return GHOST_kSuccess;
1207 }
1208
1209 return GHOST_kFailure;
1210}
1211
1212#ifdef WITH_INPUT_IME
1213void GHOST_WindowWin32::beginIME(int32_t x, int32_t y, int32_t /*w*/, int32_t h, bool completed)
1214{
1215 ime_input_.BeginIME(h_wnd_, GHOST_Rect(x, y - h, x, y), completed);
1216}
1217
1218void GHOST_WindowWin32::endIME()
1219{
1220 ime_input_.EndIME(h_wnd_);
1221}
1222#endif /* WITH_INPUT_IME */
1223
1224void GHOST_WindowWin32::registerWindowAppUserModelProperties()
1225{
1226 IPropertyStore *pstore;
1227 char blender_path[MAX_PATH];
1228 wchar_t shell_command[MAX_PATH];
1229
1230 /* Find the current executable, and see if it's blender.exe if not bail out. */
1231 GetModuleFileName(0, blender_path, sizeof(blender_path));
1232 char *blender_app = strstr(blender_path, "blender.exe");
1233 if (!blender_app) {
1234 return;
1235 }
1236
1237 HRESULT hr = SHGetPropertyStoreForWindow(h_wnd_, IID_PPV_ARGS(&pstore));
1238 if (!SUCCEEDED(hr)) {
1239 return;
1240 }
1241
1242 /* Set the launcher as the shell command so the console window will not flash.
1243 * when people pin blender to the taskbar. */
1244 strcpy(blender_app, "blender-launcher.exe");
1245 wsprintfW(shell_command, L"\"%S\"", blender_path);
1246 UTF16_ENCODE(BLENDER_WIN_APPID);
1247 UTF16_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1248 PROPVARIANT propvar;
1249 hr = InitPropVariantFromString(BLENDER_WIN_APPID_16, &propvar);
1250 hr = pstore->SetValue(PKEY_AppUserModel_ID, propvar);
1251 hr = InitPropVariantFromString(shell_command, &propvar);
1252 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, propvar);
1253 hr = InitPropVariantFromString(BLENDER_WIN_APPID_FRIENDLY_NAME_16, &propvar);
1254 hr = pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, propvar);
1255 pstore->Release();
1256 UTF16_UN_ENCODE(BLENDER_WIN_APPID_FRIENDLY_NAME);
1257 UTF16_UN_ENCODE(BLENDER_WIN_APPID);
1258}
1259
1260/* as per MSDN: Any property not cleared before closing the window, will be leaked and NOT be
1261 * returned to the OS. */
1262void GHOST_WindowWin32::unregisterWindowAppUserModelProperties()
1263{
1264 IPropertyStore *pstore;
1265 HRESULT hr = SHGetPropertyStoreForWindow(h_wnd_, IID_PPV_ARGS(&pstore));
1266 if (SUCCEEDED(hr)) {
1267 PROPVARIANT value;
1268 PropVariantInit(&value);
1269 pstore->SetValue(PKEY_AppUserModel_ID, value);
1270 pstore->SetValue(PKEY_AppUserModel_RelaunchCommand, value);
1271 pstore->SetValue(PKEY_AppUserModel_RelaunchDisplayNameResource, value);
1272 pstore->Release();
1273 }
1274}
1275
1276/* We call this from a few window event changes, but actually none of them immediately
1277 * respond to SDR white level changes in the system. That requires using the WinRT API,
1278 * which we don't do so far. */
1280{
1281 /* Get monitor from window. */
1282 HMONITOR hmonitor = ::MonitorFromWindow(h_wnd_, MONITOR_DEFAULTTONEAREST);
1283 if (!hmonitor) {
1284 return;
1285 }
1286
1287 MONITORINFOEXW monitor_info = {};
1288 monitor_info.cbSize = sizeof(MONITORINFOEXW);
1289 if (!::GetMonitorInfoW(hmonitor, &monitor_info)) {
1290 return;
1291 }
1292
1293 /* Get active display paths and modes. */
1294 UINT32 path_count = 0;
1295 UINT32 mode_count = 0;
1296 if (::GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) !=
1297 ERROR_SUCCESS)
1298 {
1299 return;
1300 }
1301
1302 std::vector<DISPLAYCONFIG_PATH_INFO> paths(path_count);
1303 std::vector<DISPLAYCONFIG_MODE_INFO> modes(mode_count);
1304 if (::QueryDisplayConfig(
1305 QDC_ONLY_ACTIVE_PATHS, &path_count, paths.data(), &mode_count, modes.data(), nullptr) !=
1306 ERROR_SUCCESS)
1307 {
1308 return;
1309 }
1310
1312
1313 /* Find the display path matching the monitor. */
1314 for (const DISPLAYCONFIG_PATH_INFO &path : paths) {
1315 DISPLAYCONFIG_SOURCE_DEVICE_NAME device_name = {};
1316 device_name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
1317 device_name.header.size = sizeof(device_name);
1318 device_name.header.adapterId = path.sourceInfo.adapterId;
1319 device_name.header.id = path.sourceInfo.id;
1320
1321 if (::DisplayConfigGetDeviceInfo(&device_name.header) != ERROR_SUCCESS) {
1322 continue;
1323 }
1324 if (wcscmp(monitor_info.szDevice, device_name.viewGdiDeviceName) != 0) {
1325 continue;
1326 }
1327
1328 /* Query HDR status. */
1329 DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO color_info = {};
1330 color_info.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
1331 color_info.header.size = sizeof(color_info);
1332 color_info.header.adapterId = path.targetInfo.adapterId;
1333 color_info.header.id = path.targetInfo.id;
1334
1335 if (::DisplayConfigGetDeviceInfo(&color_info.header) == ERROR_SUCCESS) {
1336 /* This particular combination indicates HDR mode is enabled. This is undocumented but
1337 * used by WinRT. When wideColorEnforced is true we are in SDR mode with advanced color. */
1338 info.wide_gamut_enabled = color_info.advancedColorSupported &&
1339 color_info.advancedColorEnabled;
1340 info.hdr_enabled = info.wide_gamut_enabled && !color_info.wideColorEnforced;
1341 }
1342
1343 if (info.hdr_enabled) {
1344 /* Query SDR white level. */
1345 DISPLAYCONFIG_SDR_WHITE_LEVEL white_level = {};
1346 white_level.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
1347 white_level.header.size = sizeof(white_level);
1348 white_level.header.adapterId = path.targetInfo.adapterId;
1349 white_level.header.id = path.targetInfo.id;
1350
1351 if (::DisplayConfigGetDeviceInfo(&white_level.header) == ERROR_SUCCESS) {
1352 if (white_level.SDRWhiteLevel > 0) {
1353 /* Windows assumes 1.0 = 80 nits, so multipley by that to get the absolute
1354 * value in nits if we need it in the future. */
1355 info.sdr_white_level = static_cast<float>(white_level.SDRWhiteLevel) / 1000.0f;
1356 }
1357 }
1358 }
1359
1360 hdr_info_ = info;
1361 }
1362}
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_kStandardCursorBottomLeftCorner
@ GHOST_kStandardCursorHelp
@ GHOST_kStandardCursorWait
@ GHOST_kStandardCursorTopSide
@ GHOST_kStandardCursorCustom
@ GHOST_kStandardCursorTopLeftCorner
@ GHOST_kStandardCursorMove
@ GHOST_kStandardCursorBottomRightCorner
@ GHOST_kStandardCursorDefault
@ GHOST_kStandardCursorTopRightCorner
@ GHOST_kStandardCursorText
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
@ GHOST_kTabletModeEraser
@ GHOST_kTabletModeStylus
GHOST_TDrawingContextType
GHOST_TWindowOrder
@ GHOST_kWindowOrderBottom
GHOST_TSuccess
Definition GHOST_Types.h:57
@ GHOST_kFailure
Definition GHOST_Types.h:57
@ GHOST_kSuccess
Definition GHOST_Types.h:57
#define GHOST_WINDOW_HDR_INFO_NONE
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,...)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
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_TSuccess setClientSize(uint32_t width, uint32_t height)
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
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, const GHOST_ContextParams &context_params, GHOST_WindowWin32 *parent_window, bool dialog, const GHOST_GPUDevice &preferred_device)
void loadCursor(bool visible, GHOST_TStandardCursor cursor_shape) const
void adjustWindowRectForClosestMonitor(LPRECT win_rect, DWORD dwStyle, DWORD dwExStyle)
GHOST_ContextParams want_context_params_
void setCursorGrabAccum(int32_t x, int32_t y)
GHOST_WindowDecorationStyleSettings window_decoration_style_settings_
GHOST_TStandardCursor getCursorShape() const override
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override
int32_t cursor_grab_init_pos_[2]
GHOST_TSuccess releaseNativeHandles()
GHOST_TWindowDecorationStyleFlags window_decoration_style_flags_
bool getValid() const override
bool getCursorVisibility() const override
GHOST_Window(uint32_t width, uint32_t height, GHOST_TWindowState state, const GHOST_ContextParams &context_params, const bool exclusive=false)
GHOST_Rect cursor_grab_bounds_
GHOST_WindowHDRInfo hdr_info_
GHOST_TGrabCursorMode cursor_grab_
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)
#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:294
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
PointerRNA * ptr
Definition wm_files.cc:4238