29 #define WM_DPICHANGED 0x02E0
33 #define WM_TOUCH 0x0240
38 #define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
43 DECLARE_HANDLE(HTOUCHINPUT);
47 TypeHandle WinGraphicsWindow::WinWindowHandle::_type_handle;
49 WinGraphicsWindow::WindowHandles WinGraphicsWindow::_window_handles;
53 bool WinGraphicsWindow::_cursor_hidden =
false;
55 RECT WinGraphicsWindow::_mouse_unconfined_cliprect;
60 bool WinGraphicsWindow::_got_saved_params =
false;
61 int WinGraphicsWindow::_saved_mouse_trails;
62 BOOL WinGraphicsWindow::_saved_cursor_shadow;
63 BOOL WinGraphicsWindow::_saved_mouse_vanish;
69 int WinGraphicsWindow::_window_class_index = 0;
71 static const char *
const errorbox_title =
"Panda3D Error";
75 typedef BOOL (WINAPI *PFN_REGISTERTOUCHWINDOW)(IN HWND hWnd, IN ULONG ulFlags);
76 typedef BOOL (WINAPI *PFN_GETTOUCHINPUTINFO)(IN HTOUCHINPUT hTouchInput, IN UINT cInputs, OUT PTOUCHINPUT pInputs, IN
int cbSize);
77 typedef BOOL (WINAPI *PFN_CLOSETOUCHINPUTHANDLE)(IN HTOUCHINPUT hTouchInput);
79 static PFN_REGISTERTOUCHWINDOW pRegisterTouchWindow = 0;
80 static PFN_GETTOUCHINPUTINFO pGetTouchInputInfo = 0;
81 static PFN_CLOSETOUCHINPUTHANDLE pCloseTouchInputHandle = 0;
88 const std::string &name,
94 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
96 initialize_input_devices();
100 _tracking_mouse_leaving =
false;
102 _lost_keypresses =
false;
103 _lshift_down =
false;
104 _rshift_down =
false;
105 _lcontrol_down =
false;
106 _rcontrol_down =
false;
117 ~WinGraphicsWindow() {
118 if (_window_handle !=
nullptr) {
119 DCAST(WinWindowHandle, _window_handle)->clear_window();
131 nassertr(device >= 0 && device < (
int)_input_devices.size(),
MouseData());
137 if (device == 0 && result._in_window && GetCursorPos(&cpos) && ScreenToClient(_hWnd, &cpos)) {
139 result._xpos = cpos.x;
140 result._ypos = cpos.y;
166 if (!_properties.get_foreground() )
177 SetCursorPos(view_rect.left + x, view_rect.top + y);
182 if ((device < 1)||(device >= (
int)_input_devices.size())) {
200 HIMC hIMC = ImmGetContext(_hWnd);
202 if (!ImmSetOpenStatus(hIMC,
false)) {
203 windisplay_cat.debug() <<
"ImmSetOpenStatus failed\n";
205 ImmReleaseContext(_hWnd, hIMC);
209 windisplay_cat.debug() <<
"success: closed ime window\n";
257 if (!disable_message_loop) {
260 while (PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
301 if (_parent_window_handle ==
nullptr) {
302 LPoint2i top_left = _properties.get_origin();
303 LPoint2i bottom_right = top_left + _properties.get_size();
305 DWORD window_style = make_style(_properties);
306 SetWindowLong(_hWnd, GWL_STYLE, window_style);
310 SetRect(&view_rect, top_left[0], top_left[1],
311 bottom_right[0], bottom_right[1]);
313 GetWindowInfo(_hWnd, &wi);
314 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
317 SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
318 view_rect.right - view_rect.left,
319 view_rect.bottom - view_rect.top,
320 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
321 SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
326 std::string title = properties.
get_title();
327 _properties.set_title(title);
330 SetWindowTextW(_hWnd, title_w.c_str());
337 ::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
338 ::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
347 _properties.set_cursor_hidden(hide_cursor);
348 if (_cursor_window ==
this) {
349 hide_or_show_cursor(hide_cursor);
357 _properties.set_cursor_filename(filename);
359 _cursor = get_cursor(filename);
361 _cursor = LoadCursor(
nullptr, IDC_ARROW);
364 if (_cursor_window ==
this) {
372 WindowProperties::ZOrder last_z_order = _properties.get_z_order();
374 adjust_z_order(last_z_order, properties.
get_z_order());
380 if (!SetActiveWindow(_hWnd)) {
381 windisplay_cat.warning()
382 <<
"SetForegroundWindow() failed!\n";
384 _properties.set_foreground(
true);
391 if (_properties.get_minimized() != properties.
get_minimized()) {
393 ShowWindow(_hWnd, SW_MINIMIZE);
395 ShowWindow(_hWnd, SW_RESTORE);
405 if (do_fullscreen_switch()){
406 _properties.set_fullscreen(
true);
409 windisplay_cat.warning()
410 <<
"Switching to fullscreen mode failed!\n";
413 if (do_windowed_switch()){
414 _properties.set_fullscreen(
false);
417 windisplay_cat.warning()
418 <<
"Switching to windowed mode failed!\n";
423 if (properties.has_mouse_mode()) {
424 if (properties.
get_mouse_mode() != _properties.get_mouse_mode()) {
426 case WindowProperties::M_absolute:
427 case WindowProperties::M_relative:
429 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
431 windisplay_cat.info() <<
"Unconfining cursor from window\n";
433 _properties.set_mouse_mode(WindowProperties::M_absolute);
436 case WindowProperties::M_confined:
439 if (GetForegroundWindow() != _hWnd || confine_cursor()) {
440 _properties.set_mouse_mode(WindowProperties::M_confined);
454 void WinGraphicsWindow::
456 GraphicsWindow::trigger_flip();
462 InvalidateRect(_hWnd,
nullptr, FALSE);
463 _got_expose_event =
false;
465 if (windisplay_cat.is_spam()) {
466 windisplay_cat.spam()
467 <<
"InvalidateRect: " <<
this <<
"\n";
475 void WinGraphicsWindow::
477 set_cursor_out_of_window();
478 DestroyWindow(_hWnd);
480 if (_properties.has_mouse_mode() &&
481 _properties.get_mouse_mode() == WindowProperties::M_confined) {
487 do_fullscreen_disable();
491 _window_handles.erase(_hWnd);
494 GraphicsWindow::close_window();
501 bool WinGraphicsWindow::
503 if (_properties.has_cursor_filename()) {
504 _cursor = get_cursor(_properties.get_cursor_filename());
507 _cursor = LoadCursor(
nullptr, IDC_ARROW);
509 bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
510 bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
512 HWND old_foreground_window = GetForegroundWindow();
517 _creating_window =
this;
518 bool opened = open_graphic_window();
519 _creating_window =
nullptr;
527 _window_handles.insert(WindowHandles::value_type(_hWnd,
this));
530 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
531 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
534 if (want_minimized) {
535 ShowWindow(_hWnd, SW_MINIMIZE);
536 ShowWindow(_hWnd, SW_MINIMIZE);
538 ShowWindow(_hWnd, SW_SHOWNORMAL);
539 ShowWindow(_hWnd, SW_SHOWNORMAL);
542 HWND new_foreground_window = _hWnd;
543 if (!want_foreground) {
546 new_foreground_window = old_foreground_window;
549 if (!SetActiveWindow(new_foreground_window)) {
550 windisplay_cat.warning()
551 <<
"SetActiveWindow() failed!\n";
557 if (!SetForegroundWindow(new_foreground_window)) {
558 windisplay_cat.warning()
559 <<
"SetForegroundWindow() failed!\n";
565 HIMC hIMC = ImmGetContext(_hWnd);
567 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
568 ImmReleaseContext(_hWnd, hIMC);
572 if (_input_devices.size() > 1) {
574 Rid.usUsagePage = 0x01;
577 Rid.hwndTarget = _hWnd;
578 RegisterRawInputDevices(&Rid, 1,
sizeof (Rid));
582 _window_handle = NativeWindowHandle::make_win(_hWnd);
585 _window_handle =
new WinWindowHandle(
this, *_window_handle);
588 if (_parent_window_handle !=
nullptr) {
589 _parent_window_handle->attach_child(_window_handle);
596 static bool initialized =
false;
599 HMODULE user32 = GetModuleHandleA(
"user32.dll");
602 pRegisterTouchWindow = (PFN_REGISTERTOUCHWINDOW)GetProcAddress(user32,
"RegisterTouchWindow");
603 pGetTouchInputInfo = (PFN_GETTOUCHINPUTINFO)GetProcAddress(user32,
"GetTouchInputInfo");
604 pCloseTouchInputHandle = (PFN_CLOSETOUCHINPUTHANDLE)GetProcAddress(user32,
"CloseTouchInputHandle");
609 if (pRegisterTouchWindow !=
nullptr) {
610 pRegisterTouchWindow(_hWnd, 0);
622 void WinGraphicsWindow::
623 initialize_input_devices() {
625 PRAWINPUTDEVICELIST pRawInputDeviceList;
627 nassertv(_input_devices.size() == 0);
630 memset(_input_device_handle, 0,
sizeof(_input_device_handle));
632 GraphicsWindowInputDevice::pointer_and_keyboard(
this,
"keyboard_mouse");
633 add_input_device(device);
637 if (GetRawInputDeviceList(
nullptr, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) != 0) {
642 pRawInputDeviceList = (PRAWINPUTDEVICELIST)alloca(
sizeof(RAWINPUTDEVICELIST) * nInputDevices);
643 if (pRawInputDeviceList==0) {
648 if (GetRawInputDeviceList(pRawInputDeviceList, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) == -1) {
653 for (
int i = 0; i < (int)nInputDevices; i++) {
654 if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) {
657 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)0, &nSize) != 0) {
660 char *psName = (
char*)alloca(
sizeof(TCHAR) * nSize);
661 if (psName == 0)
return;
662 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)psName, &nSize) < 0) {
667 if (strncmp(psName,
"\\??\\Root#RDP_MOU#0000#",22)!=0) {
668 if (_input_devices.size() < 32) {
669 if (strncmp(psName,
"\\??\\",4)==0) psName += 4;
670 char *pound1 = strchr(psName,
'#');
671 char *pound2 = pound1 ? strchr(pound1+1,
'#') : 0;
672 char *pound3 = pound2 ? strchr(pound2+1,
'#') : 0;
673 if (pound3) *pound3 = 0;
674 for (
char *p = psName; *p; p++) {
679 if (pound2) *pound2 =
'.';
680 _input_device_handle[_input_devices.size()] = pRawInputDeviceList[i].hDevice;
683 device->set_pointer_in_window(0, 0);
684 add_input_device(device);
697 void WinGraphicsWindow::
707 void WinGraphicsWindow::
717 bool WinGraphicsWindow::
718 do_reshape_request(
int x_origin,
int y_origin,
bool has_origin,
719 int x_size,
int y_size) {
720 if (windisplay_cat.is_debug()) {
721 windisplay_cat.debug()
722 <<
"Got reshape request (" << x_origin <<
", " << y_origin
723 <<
", " << has_origin <<
", " << x_size <<
", " << y_size <<
")\n";
728 if (x_origin == -2) {
729 x_origin = 0.5 * (_pipe->get_display_width() - x_size);
731 if (y_origin == -2) {
732 y_origin = 0.5 * (_pipe->get_display_height() - y_size);
734 _properties.set_origin(x_origin, y_origin);
736 if (x_origin == -1 && y_origin == -1) {
746 SetRect(&view_rect, x_origin, y_origin,
747 x_origin + x_size, y_origin + y_size);
749 GetWindowInfo(_hWnd, &wi);
750 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
752 UINT flags = SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE;
755 x_origin = view_rect.left;
756 y_origin = view_rect.top;
758 x_origin = CW_USEDEFAULT;
759 y_origin = CW_USEDEFAULT;
763 SetWindowPos(_hWnd,
nullptr, x_origin, y_origin,
764 view_rect.right - view_rect.left,
765 view_rect.bottom - view_rect.top,
773 return do_fullscreen_resize(x_size, y_size);
780 void WinGraphicsWindow::
783 if (!GetClientRect(_hWnd, &view_rect)) {
786 if (windisplay_cat.is_debug()) {
787 windisplay_cat.debug()
788 <<
"GetClientRect() failed in handle_reshape. Ignoring.\n";
795 if (view_rect.left == 0 && view_rect.right == 0 &&
796 view_rect.bottom == 0 && view_rect.top == 0) {
797 if (windisplay_cat.is_debug()) {
798 windisplay_cat.debug()
799 <<
"GetClientRect() returned all zeroes in handle_reshape. Ignoring.\n";
804 bool result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.left));
806 result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.right));
810 if (windisplay_cat.is_debug()) {
811 windisplay_cat.debug()
812 <<
"ClientToScreen() failed in handle_reshape. Ignoring.\n";
822 if (_properties.has_mouse_mode() &&
823 _properties.get_mouse_mode() == WindowProperties::M_confined &&
824 _hWnd == GetForegroundWindow()) {
827 if (GetCursorPos(&cpos) && PtInRect(&view_rect, cpos)) {
828 windisplay_cat.info()
829 <<
"ClipCursor() to " << view_rect.left <<
"," << view_rect.top
830 <<
" to " << view_rect.right <<
"," << view_rect.bottom << endl;
832 if (!ClipCursor(&view_rect)) {
833 windisplay_cat.warning()
834 <<
"Failed to re-confine cursor to window.\n";
840 properties.
set_size((view_rect.right - view_rect.left),
841 (view_rect.bottom - view_rect.top));
844 properties.
set_origin(view_rect.left, view_rect.top);
846 if (windisplay_cat.is_debug()) {
847 windisplay_cat.debug()
848 <<
"reshape to origin: (" << properties.
get_x_origin() <<
","
854 system_changed_properties(properties);
860 bool WinGraphicsWindow::
861 do_fullscreen_resize(
int x_size,
int y_size) {
862 HWND hDesktopWindow = GetDesktopWindow();
863 HDC scrnDC = GetDC(hDesktopWindow);
864 DWORD dwFullScreenBitDepth = GetDeviceCaps(scrnDC, BITSPIXEL);
865 ReleaseDC(hDesktopWindow, scrnDC);
873 if (!find_acceptable_display_mode(x_size, y_size,
874 dwFullScreenBitDepth, dm)) {
875 windisplay_cat.error()
876 <<
"window resize(" << x_size <<
", " << y_size
877 <<
") failed, no compatible fullscreen display mode found!\n";
882 SetWindowPos(_hWnd,
nullptr, 0,0, x_size, y_size,
883 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
884 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
886 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
887 windisplay_cat.error()
888 <<
"resize ChangeDisplaySettings failed (error code: "
889 << chg_result <<
") for specified res: "
890 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
891 <<
" x " << dm.dmBitsPerPel <<
", "
892 << dm.dmDisplayFrequency <<
" Hz\n";
896 _fullscreen_display_mode = dm;
898 windisplay_cat.info()
899 <<
"Resized fullscreen window to " << x_size <<
", " << y_size
900 <<
" bitdepth " << dwFullScreenBitDepth <<
", "
901 << dm.dmDisplayFrequency <<
"Hz\n";
903 _properties.set_size(x_size, y_size);
912 bool WinGraphicsWindow::
913 do_fullscreen_switch() {
914 if (!do_fullscreen_enable()) {
920 props.set_fullscreen(
true);
921 DWORD window_style = make_style(props);
922 SetWindowLong(_hWnd, GWL_STYLE, window_style);
924 WINDOW_METRICS metrics;
926 if (!calculate_metrics(
true, window_style, metrics, has_origin)){
930 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, metrics.width, metrics.height,
931 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
938 bool WinGraphicsWindow::
939 do_windowed_switch() {
940 do_fullscreen_disable();
943 props.set_fullscreen(
false);
944 DWORD window_style = make_style(props);
945 SetWindowLong(_hWnd, GWL_STYLE, window_style);
947 WINDOW_METRICS metrics;
950 if (!calculate_metrics(
false, window_style, metrics, has_origin)){
958 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0,
959 metrics.width, metrics.height,
960 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
963 if (_properties.has_mouse_mode() &&
964 _properties.get_mouse_mode() == WindowProperties::M_confined) {
975 void WinGraphicsWindow::
976 reconsider_fullscreen_size(DWORD &, DWORD &, DWORD &) {
985 void WinGraphicsWindow::
986 support_overlay_window(
bool) {
992 DWORD WinGraphicsWindow::
1001 DWORD window_style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
1004 window_style |= WS_POPUP | WS_SYSMENU;
1006 else if (_parent_window_handle) {
1007 window_style |= WS_CHILD;
1010 window_style |= WS_POPUP;
1013 window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
1016 window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX);
1018 window_style |= WS_BORDER;
1022 return window_style;
1029 bool WinGraphicsWindow::
1030 calculate_metrics(
bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
1034 has_origin = _properties.has_origin();
1035 if (!fullscreen && has_origin) {
1036 metrics.x = _properties.get_x_origin();
1037 metrics.y = _properties.get_y_origin();
1040 if (metrics.x == -2) {
1041 metrics.x = 0.5 * (_pipe->get_display_width() - _properties.get_x_size());
1043 if (metrics.y == -2) {
1044 metrics.y = 0.5 * (_pipe->get_display_height() - _properties.get_y_size());
1046 _properties.set_origin(metrics.x, metrics.y);
1048 if (metrics.x == -1 && metrics.y == -1) {
1055 metrics.width = _properties.get_x_size();
1056 metrics.height = _properties.get_y_size();
1060 SetRect(&win_rect, metrics.x, metrics.y,
1061 metrics.x + metrics.width, metrics.y + metrics.height);
1064 if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
1065 windisplay_cat.error()
1066 <<
"AdjustWindowRect failed!" << endl;
1071 metrics.x = win_rect.left;
1072 metrics.y = win_rect.top;
1074 metrics.x = CW_USEDEFAULT;
1075 metrics.y = CW_USEDEFAULT;
1077 metrics.width = win_rect.right - win_rect.left;
1078 metrics.height = win_rect.bottom - win_rect.top;
1087 bool WinGraphicsWindow::
1088 open_graphic_window() {
1089 DWORD window_style = make_style(_properties);
1092 if (_properties.has_title()) {
1094 title = encoder.
decode_text(_properties.get_title());
1097 if (!_properties.has_size()) {
1099 _properties.set_size(640, 480);
1102 WINDOW_METRICS metrics;
1104 if (!calculate_metrics(fullscreen, window_style, metrics, has_origin)){
1108 const WindowClass &wclass = register_window_class(_properties);
1109 HINSTANCE hinstance = GetModuleHandle(
nullptr);
1114 WindowHandle *window_handle = _properties.get_parent_window();
1115 if (window_handle !=
nullptr) {
1116 windisplay_cat.info()
1117 <<
"Got parent_window " << *window_handle <<
"\n";
1119 if (os_handle !=
nullptr) {
1120 windisplay_cat.info()
1121 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1123 if (os_handle->
is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
1124 NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
1125 _hparent = win_handle->get_handle();
1126 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1128 _hparent = (HWND)int_handle->get_handle();
1132 _parent_window_handle = window_handle;
1134 _parent_window_handle =
nullptr;
1138 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(), window_style,
1139 metrics.x, metrics.y,
1142 nullptr,
nullptr, hinstance, 0);
1147 if (!fullscreen && has_origin) {
1148 x_origin = _properties.get_x_origin();
1149 y_origin = _properties.get_y_origin();
1152 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(),
1153 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ,
1155 _properties.get_x_size(), _properties.get_y_size(),
1156 _hparent,
nullptr, hinstance, 0);
1169 system_changed_properties(properties);
1174 windisplay_cat.error()
1175 <<
"CreateWindow() failed!" << endl;
1176 show_error_message();
1185 if (!do_fullscreen_enable()){
1197 bool WinGraphicsWindow::
1198 do_fullscreen_enable() {
1200 HWND hDesktopWindow = GetDesktopWindow();
1201 HDC scrnDC = GetDC(hDesktopWindow);
1202 DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
1206 ReleaseDC(hDesktopWindow, scrnDC);
1208 DWORD dwWidth = _properties.get_x_size();
1209 DWORD dwHeight = _properties.get_y_size();
1210 DWORD dwFullScreenBitDepth = cur_bitdepth;
1213 reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
1214 if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth, dm)) {
1215 windisplay_cat.error()
1216 <<
"Videocard has no supported display resolutions at specified res ("
1217 << dwWidth <<
" x " << dwHeight <<
" x " << dwFullScreenBitDepth <<
")\n";
1221 dm.dmPelsWidth = dwWidth;
1222 dm.dmPelsHeight = dwHeight;
1223 dm.dmBitsPerPel = dwFullScreenBitDepth;
1224 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1226 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1227 windisplay_cat.error()
1228 <<
"ChangeDisplaySettings failed (error code: "
1229 << chg_result <<
") for specified res: "
1230 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1231 <<
" x " << dm.dmBitsPerPel <<
", "
1232 << dm.dmDisplayFrequency <<
" Hz\n";
1236 _fullscreen_display_mode = dm;
1238 _properties.set_origin(0, 0);
1239 _properties.set_size(dwWidth, dwHeight);
1249 bool WinGraphicsWindow::
1250 do_fullscreen_disable() {
1251 int chg_result = ChangeDisplaySettings(
nullptr, 0x0);
1252 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1253 windisplay_cat.warning()
1254 <<
"ChangeDisplaySettings failed to restore Windowed mode\n";
1263 void WinGraphicsWindow::
1265 WindowProperties::ZOrder z_order = _properties.get_z_order();
1266 adjust_z_order(z_order, z_order);
1272 void WinGraphicsWindow::
1273 adjust_z_order(WindowProperties::ZOrder last_z_order,
1274 WindowProperties::ZOrder this_z_order) {
1276 bool do_change =
false;
1278 switch (this_z_order) {
1279 case WindowProperties::Z_bottom:
1280 order = HWND_BOTTOM;
1284 case WindowProperties::Z_normal:
1285 if ((last_z_order != WindowProperties::Z_normal) &&
1287 (last_z_order != WindowProperties::Z_bottom ||
1288 _properties.get_foreground())
1293 order = HWND_NOTOPMOST;
1298 case WindowProperties::Z_top:
1299 order = HWND_TOPMOST;
1304 BOOL result = SetWindowPos(_hWnd, order, 0,0,0,0,
1305 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
1307 windisplay_cat.warning()
1308 <<
"SetWindowPos failed.\n";
1318 void WinGraphicsWindow::
1319 track_mouse_leaving(HWND hwnd) {
1321 DCAST_INTO_V(winpipe, _pipe);
1323 TRACKMOUSEEVENT tme = {
1324 sizeof(TRACKMOUSEEVENT),
1331 BOOL bSucceeded = TrackMouseEvent(&tme);
1333 if (!bSucceeded && windisplay_cat.is_debug()) {
1334 windisplay_cat.debug()
1335 <<
"TrackMouseEvent failed!, LastError=" << GetLastError() << endl;
1338 _tracking_mouse_leaving =
true;
1344 bool WinGraphicsWindow::
1349 windisplay_cat.info()
1350 <<
"ClipCursor() to " << clip.left <<
"," << clip.top <<
" to "
1351 << clip.right <<
"," << clip.bottom << endl;
1353 if (!ClipCursor(&clip)) {
1354 windisplay_cat.warning()
1355 <<
"Failed to confine cursor to window.\n";
1366 void WinGraphicsWindow::
1368 if (SetFocus(_hWnd) ==
nullptr && GetLastError() != 0) {
1374 if (_parent_window_handle !=
nullptr && _window_handle !=
nullptr) {
1375 _parent_window_handle->request_keyboard_focus(_window_handle);
1378 windisplay_cat.error()
1379 <<
"SetFocus failed: " << GetLastError() <<
"\n";
1405 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1406 if (windisplay_cat.is_spam()) {
1407 windisplay_cat.spam()
1409 <<
" window_proc(" << (
void *)
this <<
", " << hwnd <<
", "
1410 << msg <<
", " << wparam <<
", " << lparam <<
")\n";
1416 if (!_tracking_mouse_leaving) {
1418 track_mouse_leaving(hwnd);
1420 set_cursor_in_window();
1421 if(handle_mouse_motion(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))))
1426 handle_raw_input((HRAWINPUT)lparam);
1430 _tracking_mouse_leaving =
false;
1431 handle_mouse_exit();
1432 set_cursor_out_of_window();
1437 track_mouse_leaving(hwnd);
1438 ClearToBlack(hwnd, _properties);
1441 GetCursorPos(&cpos);
1442 ScreenToClient(hwnd, &cpos);
1444 GetClientRect(hwnd, &clientRect);
1445 if (PtInRect(&clientRect,cpos)) {
1446 set_cursor_in_window();
1448 set_cursor_out_of_window();
1481 if (!close_request_event.empty()) {
1484 throw_event(close_request_event);
1492 system_changed_properties(properties);
1499 case WM_CHILDACTIVATE:
1500 if (windisplay_cat.is_debug()) {
1501 windisplay_cat.debug()
1502 <<
"WM_CHILDACTIVATE: " << hwnd <<
"\n";
1507 if (windisplay_cat.is_debug()) {
1508 windisplay_cat.debug()
1509 <<
"WM_ACTIVATE: " << hwnd <<
", " << wparam <<
", " << lparam <<
"\n";
1512 if ((wparam & 0xffff) != WA_INACTIVE)
1520 ChangeDisplaySettings(&_fullscreen_display_mode, CDS_FULLSCREEN);
1521 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1522 const DEVMODE &dm = _fullscreen_display_mode;
1523 windisplay_cat.error()
1524 <<
"restore ChangeDisplaySettings failed (error code: "
1525 << chg_result <<
") for specified res: "
1526 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1527 <<
" x " << dm.dmBitsPerPel <<
", "
1528 << dm.dmDisplayFrequency <<
" Hz\n";
1532 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
1533 fullscreen_restored(properties);
1537 if (_properties.has_mouse_mode() &&
1538 _properties.get_mouse_mode() == WindowProperties::M_confined) {
1539 if (!confine_cursor()) {
1556 ShowWindow(_hWnd, SW_MINIMIZE);
1558 do_fullscreen_disable();
1559 fullscreen_minimized(properties);
1564 system_changed_properties(properties);
1570 if (windisplay_cat.is_debug()) {
1571 windisplay_cat.debug()
1572 <<
"WM_SIZE: " << hwnd <<
", " << wparam <<
"\n";
1576 case WM_EXITSIZEMOVE:
1577 if (windisplay_cat.is_debug()) {
1578 windisplay_cat.debug()
1579 <<
"WM_EXITSIZEMOVE: " << hwnd <<
", " << wparam <<
"\n";
1583 if (_properties.has_mouse_mode() &&
1584 _properties.get_mouse_mode() == WindowProperties::M_confined) {
1589 case WM_WINDOWPOSCHANGED:
1590 if (windisplay_cat.is_debug()) {
1591 windisplay_cat.debug()
1592 <<
"WM_WINDOWPOSCHANGED: " << hwnd <<
", " << wparam <<
"\n";
1594 if (_hWnd !=
nullptr) {
1604 if (GetUpdateRect(_hWnd,
nullptr,
false)) {
1605 if (windisplay_cat.is_spam()) {
1606 windisplay_cat.spam()
1607 <<
"Got update regions: " <<
this <<
"\n";
1609 _got_expose_event =
true;
1613 case WM_LBUTTONDOWN:
1614 if (_lost_keypresses) {
1615 resend_lost_keypresses();
1625 case WM_MBUTTONDOWN:
1626 if (_lost_keypresses) {
1627 resend_lost_keypresses();
1636 case WM_RBUTTONDOWN:
1637 if (_lost_keypresses) {
1638 resend_lost_keypresses();
1647 case WM_XBUTTONDOWN:
1649 if (_lost_keypresses) {
1650 resend_lost_keypresses();
1653 int whichButton = GET_XBUTTON_WPARAM(wparam);
1655 if (whichButton == XBUTTON1) {
1657 }
else if (whichButton == XBUTTON2) {
1664 if (_lost_keypresses) {
1665 resend_lost_keypresses();
1672 if (_lost_keypresses) {
1673 resend_lost_keypresses();
1680 if (_lost_keypresses) {
1681 resend_lost_keypresses();
1689 if (_lost_keypresses) {
1690 resend_lost_keypresses();
1693 int whichButton = GET_XBUTTON_WPARAM(wparam);
1694 if (whichButton == XBUTTON1) {
1696 }
else if (whichButton == XBUTTON2) {
1704 int delta = GET_WHEEL_DELTA_WPARAM(wparam);
1707 GetCursorPos(&point);
1708 ScreenToClient(hwnd, &point);
1709 double time = get_message_time();
1715 delta -= WHEEL_DELTA;
1721 delta += WHEEL_DELTA;
1729 case WM_IME_SETCONTEXT:
1733 windisplay_cat.debug() <<
"hwnd = " << hwnd <<
" and GetFocus = " << GetFocus() << endl;
1734 _ime_hWnd = ImmGetDefaultIMEWnd(hwnd);
1735 if (::SendMessage(_ime_hWnd, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0))
1737 windisplay_cat.debug() <<
"SendMessage failed for " << _ime_hWnd << endl;
1739 windisplay_cat.debug() <<
"SendMessage Succeeded for " << _ime_hWnd << endl;
1741 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1742 lparam &= ~ISC_SHOWUIALL;
1743 if (ImmIsUIMessage(_ime_hWnd, msg, wparam, lparam))
1744 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1750 if (wparam == IMN_SETOPENSTATUS) {
1751 HIMC hIMC = ImmGetContext(hwnd);
1752 nassertr(hIMC != 0, 0);
1753 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
1755 _ime_active =
false;
1759 COMPOSITIONFORM comf;
1761 ImmGetCompositionWindow(hIMC, &comf);
1762 ImmGetCandidateWindow(hIMC, 0, &canf);
1763 windisplay_cat.debug() <<
1764 "comf style " << comf.dwStyle <<
1765 " comf point: x" << comf.ptCurrentPos.x <<
",y " << comf.ptCurrentPos.y <<
1766 " comf rect: l " << comf.rcArea.left <<
",t " << comf.rcArea.top <<
",r " <<
1767 comf.rcArea.right <<
",b " << comf.rcArea.bottom << endl;
1768 windisplay_cat.debug() <<
1769 "canf style " << canf.dwStyle <<
1770 " canf point: x" << canf.ptCurrentPos.x <<
",y " << canf.ptCurrentPos.y <<
1771 " canf rect: l " << canf.rcArea.left <<
",t " << canf.rcArea.top <<
",r " <<
1772 canf.rcArea.right <<
",b " << canf.rcArea.bottom << endl;
1773 comf.dwStyle = CFS_POINT;
1774 comf.ptCurrentPos.x = 2000;
1775 comf.ptCurrentPos.y = 2000;
1777 canf.dwStyle = CFS_EXCLUDE;
1779 canf.ptCurrentPos.x = 0;
1780 canf.ptCurrentPos.y = 0;
1781 canf.rcArea.left = 0;
1782 canf.rcArea.top = 0;
1783 canf.rcArea.right = 640;
1784 canf.rcArea.bottom = 480;
1787 comf.rcArea.left = 200;
1788 comf.rcArea.top = 200;
1789 comf.rcArea.right = 0;
1790 comf.rcArea.bottom = 0;
1793 if (ImmSetCompositionWindow(hIMC, &comf))
1794 windisplay_cat.debug() <<
"set composition form: success\n";
1795 for (
int i=0; i<3; ++i) {
1796 if (ImmSetCandidateWindow(hIMC, &canf))
1797 windisplay_cat.debug() <<
"set candidate form: success\n";
1802 ImmReleaseContext(hwnd, hIMC);
1806 case WM_IME_STARTCOMPOSITION:
1807 support_overlay_window(
true);
1811 case WM_IME_ENDCOMPOSITION:
1812 support_overlay_window(
false);
1813 _ime_active =
false;
1822 case WM_IME_COMPOSITION:
1834 HIMC hIMC = ImmGetContext(hwnd);
1835 nassertr(hIMC != 0, 0);
1837 DWORD result_size = 0;
1838 static const int ime_buffer_size = 256;
1839 static const int ime_buffer_size_bytes = ime_buffer_size /
sizeof(wchar_t);
1840 wchar_t ime_buffer[ime_buffer_size];
1841 size_t cursor_pos, delta_start;
1843 if (lparam & GCS_RESULTSTR) {
1844 result_size = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
1845 ime_buffer, ime_buffer_size_bytes);
1846 size_t num_chars = result_size /
sizeof(wchar_t);
1847 for (
size_t i = 0; i < num_chars; ++i) {
1852 if (lparam & GCS_COMPSTR) {
1853 result_size = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS,
nullptr, 0);
1854 cursor_pos = result_size & 0xffff;
1856 result_size = ImmGetCompositionStringW(hIMC, GCS_DELTASTART,
nullptr, 0);
1857 delta_start = result_size & 0xffff;
1858 result_size = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, ime_buffer, ime_buffer_size);
1859 size_t num_chars = result_size /
sizeof(wchar_t);
1861 _input->
candidate(wstring(ime_buffer, num_chars),
1862 std::min(cursor_pos, delta_start),
1863 std::max(cursor_pos, delta_start),
1866 ImmReleaseContext(hwnd, hIMC);
1887 if (_lost_keypresses) {
1888 resend_lost_keypresses();
1890 if (windisplay_cat.is_debug()) {
1891 windisplay_cat.debug()
1892 <<
"syskeydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1898 GetCursorPos(&point);
1899 ScreenToClient(hwnd, &point);
1900 handle_keypress(lookup_key(wparam), point.x, point.y,
1901 get_message_time());
1903 if ((lparam & 0x40000000) == 0) {
1904 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1915 if (wparam == VK_MENU) {
1916 if ((GetKeyState(VK_LMENU) & 0x8000) != 0 && ! _lalt_down) {
1917 handle_keypress(KeyboardButton::lalt(), point.x, point.y,
1918 get_message_time());
1921 if ((GetKeyState(VK_RMENU) & 0x8000) != 0 && ! _ralt_down) {
1922 handle_keypress(KeyboardButton::ralt(), point.x, point.y,
1923 get_message_time());
1927 if (wparam == VK_F10) {
1936 if (wparam == SC_KEYMENU) {
1948 if (_lost_keypresses) {
1949 resend_lost_keypresses();
1951 if (windisplay_cat.is_debug()) {
1952 windisplay_cat.debug()
1953 <<
"keydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1958 if ((lparam & 0x40000000) == 0) {
1960 GetCursorPos(&point);
1961 ScreenToClient(hwnd, &point);
1962 handle_keypress(lookup_key(wparam), point.x, point.y,
1963 get_message_time());
1964 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1970 if (wparam == VK_SHIFT) {
1971 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0 && ! _lshift_down) {
1972 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1973 get_message_time());
1974 _lshift_down =
true;
1976 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0 && ! _rshift_down) {
1977 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1978 get_message_time());
1979 _rshift_down =
true;
1981 }
else if(wparam == VK_CONTROL) {
1982 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0 && ! _lcontrol_down) {
1983 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
1984 get_message_time());
1985 _lcontrol_down =
true;
1987 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0 && ! _rcontrol_down) {
1988 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
1989 get_message_time());
1990 _rcontrol_down =
true;
1996 if ((wparam==
'V') && (GetKeyState(VK_CONTROL) < 0) &&
1997 !_input_devices.empty() && paste_emit_keystrokes) {
2001 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(
nullptr)) {
2003 hglb = GetClipboardData(CF_TEXT);
2004 if (hglb!=
nullptr) {
2005 lptstr = (
char *) GlobalLock(hglb);
2006 if (lptstr !=
nullptr) {
2008 for (pChar = lptstr; *pChar; pChar++) {
2021 GetCursorPos(&point);
2022 ScreenToClient(hwnd, &point);
2023 handle_keypress(lookup_key(wparam), point.x, point.y,
2024 get_message_time());
2037 if (wparam == VK_SHIFT) {
2038 if (((GetKeyState(VK_LSHIFT) & 0x8000) != 0) && ! _lshift_down ) {
2039 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2040 get_message_time());
2041 _lshift_down =
true;
2042 }
else if (((GetKeyState(VK_RSHIFT) & 0x8000) != 0) && ! _rshift_down ) {
2043 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2044 get_message_time());
2045 _rshift_down =
true;
2047 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0) {
2048 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2049 get_message_time());
2051 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0) {
2052 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2053 get_message_time());
2056 }
else if(wparam == VK_CONTROL) {
2057 if (((GetKeyState(VK_LCONTROL) & 0x8000) != 0) && ! _lcontrol_down ) {
2058 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2059 get_message_time());
2060 _lcontrol_down =
true;
2061 }
else if (((GetKeyState(VK_RCONTROL) & 0x8000) != 0) && ! _rcontrol_down ) {
2062 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2063 get_message_time());
2064 _rcontrol_down =
true;
2066 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0) {
2067 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2068 get_message_time());
2070 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0) {
2071 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2072 get_message_time());
2081 if (_lost_keypresses) {
2082 resend_lost_keypresses();
2084 if (windisplay_cat.is_debug()) {
2085 windisplay_cat.debug()
2086 <<
"keyup: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
2088 handle_keyrelease(lookup_key(wparam), get_message_time());
2089 handle_raw_keyrelease(lookup_raw_key(lparam), get_message_time());
2094 if (wparam == VK_SHIFT) {
2095 if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0 && _lshift_down) {
2096 handle_keyrelease(KeyboardButton::lshift(), get_message_time());
2097 _lshift_down =
false;
2099 if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0 && _rshift_down) {
2100 handle_keyrelease(KeyboardButton::rshift(), get_message_time());
2101 _rshift_down =
false;
2103 }
else if(wparam == VK_CONTROL) {
2104 if ((GetKeyState(VK_LCONTROL) & 0x8000) == 0 && _lcontrol_down) {
2105 handle_keyrelease(KeyboardButton::lcontrol(), get_message_time());
2106 _lcontrol_down =
false;
2108 if ((GetKeyState(VK_RCONTROL) & 0x8000) == 0 && _rcontrol_down) {
2109 handle_keyrelease(KeyboardButton::rcontrol(), get_message_time());
2110 _rcontrol_down =
false;
2112 }
else if(wparam == VK_MENU) {
2113 if ((GetKeyState(VK_LMENU) & 0x8000) == 0 && _lalt_down) {
2114 handle_keyrelease(KeyboardButton::lalt(), get_message_time());
2117 if ((GetKeyState(VK_RMENU) & 0x8000) == 0 && _ralt_down) {
2118 handle_keyrelease(KeyboardButton::ralt(), get_message_time());
2125 if (windisplay_cat.is_debug()) {
2126 windisplay_cat.debug()
2132 system_changed_properties(properties);
2154 if (windisplay_cat.is_debug()) {
2155 windisplay_cat.debug()
2159 if (_lost_keypresses) {
2160 resend_lost_keypresses();
2164 system_changed_properties(properties);
2168 if (windisplay_cat.is_debug()) {
2169 windisplay_cat.debug()
2173 system_changed_properties(properties);
2177 if (windisplay_cat.is_debug()) {
2178 windisplay_cat.debug()
2182 system_changed_properties(properties);
2188 if (windisplay_cat.is_debug()) {
2189 windisplay_cat.debug() <<
"DPI changed to " << LOWORD(wparam);
2191 if (LOWORD(wparam) != HIWORD(wparam)) {
2192 windisplay_cat.debug(
false) <<
"x" << HIWORD(wparam) <<
"\n";
2194 windisplay_cat.debug(
false) <<
"\n";
2199 if (!_properties.get_fixed_size() && dpi_window_resize) {
2200 RECT &rect = *(LPRECT)lparam;
2201 SetWindowPos(_hWnd, HWND_TOP, rect.left, rect.top,
2202 rect.right - rect.left, rect.bottom - rect.top,
2203 SWP_NOZORDER | SWP_NOACTIVATE);
2208 _num_touches = LOWORD(wparam);
2209 if (_num_touches > MAX_TOUCHES) {
2210 _num_touches = MAX_TOUCHES;
2212 if (pGetTouchInputInfo != 0) {
2213 pGetTouchInputInfo((HTOUCHINPUT)lparam, _num_touches, _touches,
sizeof(TOUCHINPUT));
2214 pCloseTouchInputHandle((HTOUCHINPUT)lparam);
2220 for ( WinProcClasses::iterator it=_window_proc_classes.begin() ; it != _window_proc_classes.end(); it++ ){
2221 (*it)->wnd_proc(
this, hwnd, msg, wparam, lparam);
2224 return DefWindowProcW(hwnd, msg, wparam, lparam);
2235 WindowHandles::const_iterator wi;
2236 wi = _window_handles.find(hwnd);
2237 if (wi != _window_handles.end()) {
2239 return (*wi).second->window_proc(hwnd, msg, wparam, lparam);
2243 if (_creating_window !=
nullptr) {
2244 return _creating_window->
window_proc(hwnd, msg, wparam, lparam);
2249 return DefWindowProcW(hwnd, msg, wparam, lparam);
2255 void WinGraphicsWindow::
2259 if (!GetMessage(&msg,
nullptr, 0, 0)) {
2266 TranslateMessage(&msg);
2268 DispatchMessage(&msg);
2276 void WinGraphicsWindow::
2277 resend_lost_keypresses() {
2278 nassertv(_lost_keypresses);
2283 _lost_keypresses =
false;
2290 void WinGraphicsWindow::
2292 bool hide_cursor =
false;
2293 if (to_window ==
nullptr) {
2296 if (_got_saved_params) {
2297 SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails,
2299 SystemParametersInfo(SPI_SETCURSORSHADOW, 0,
2300 _saved_cursor_shadow ? (PVOID)1 :
nullptr, 0);
2301 SystemParametersInfo(SPI_SETMOUSEVANISH, 0,
2302 _saved_mouse_vanish ? (PVOID)1 :
nullptr, 0);
2303 _got_saved_params =
false;
2315 if (!_got_saved_params) {
2316 SystemParametersInfo(SPI_GETMOUSETRAILS, 0,
2317 &_saved_mouse_trails, 0);
2318 SystemParametersInfo(SPI_GETCURSORSHADOW, 0,
2319 &_saved_cursor_shadow, 0);
2320 SystemParametersInfo(SPI_GETMOUSEVANISH, 0,
2321 &_saved_mouse_vanish, 0);
2322 _got_saved_params =
true;
2324 SystemParametersInfo(SPI_SETMOUSETRAILS, 0, (PVOID)0, 0);
2325 SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (PVOID)
false, 0);
2326 SystemParametersInfo(SPI_SETMOUSEVANISH, 0, (PVOID)
false, 0);
2329 SetCursor(to_window->_cursor);
2332 hide_or_show_cursor(hide_cursor);
2334 _cursor_window = to_window;
2342 void WinGraphicsWindow::
2343 hide_or_show_cursor(
bool hide_cursor) {
2345 if (!_cursor_hidden) {
2347 _cursor_hidden =
true;
2350 if (_cursor_hidden) {
2352 _cursor_hidden =
false;
2358 #define MIN_REFRESH_RATE 60
2361 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1))
2367 bool WinGraphicsWindow::
2368 find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
2373 ZeroMemory(&cur_dm,
sizeof(cur_dm));
2374 cur_dm.dmSize =
sizeof(cur_dm);
2375 EnumDisplaySettings(
nullptr, ENUM_CURRENT_SETTINGS, &cur_dm);
2378 int saved_modenum = -1;
2381 ZeroMemory(&dm,
sizeof(dm));
2382 dm.dmSize =
sizeof(dm);
2384 if (!EnumDisplaySettings(
nullptr, modenum, &dm)) {
2388 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
2389 (dm.dmBitsPerPel == bpp)) {
2392 if (dm.dmDisplayFrequency == cur_dm.dmDisplayFrequency) {
2394 }
else if (saved_modenum == -1) {
2395 saved_modenum = modenum;
2403 if (saved_modenum != -1) {
2404 ZeroMemory(&dm,
sizeof(dm));
2405 dm.dmSize =
sizeof(dm);
2407 if (EnumDisplaySettings(
nullptr, saved_modenum, &dm)) {
2419 void WinGraphicsWindow::
2420 show_error_message(DWORD message_id) {
2421 LPTSTR message_buffer;
2423 if (message_id == 0) {
2424 message_id = GetLastError();
2427 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2428 nullptr, message_id,
2429 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2430 (LPTSTR)&message_buffer,
2432 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
2433 windisplay_cat.fatal() <<
"System error msg: " << message_buffer << endl;
2434 LocalFree(message_buffer);
2440 void WinGraphicsWindow::
2441 handle_keypress(
ButtonHandle key,
int x,
int y,
double time) {
2443 if (key != ButtonHandle::none()) {
2452 void WinGraphicsWindow::
2454 if (key != ButtonHandle::none()) {
2462 void WinGraphicsWindow::
2464 if (key != ButtonHandle::none()) {
2472 void WinGraphicsWindow::
2474 if (key != ButtonHandle::none()) {
2482 void WinGraphicsWindow::
2484 if (key != ButtonHandle::none()) {
2494 lookup_key(WPARAM wparam)
const {
2499 case VK_BACK:
return KeyboardButton::backspace();
2500 case VK_DELETE:
return KeyboardButton::del();
2501 case VK_ESCAPE:
return KeyboardButton::escape();
2502 case VK_SPACE:
return KeyboardButton::space();
2503 case VK_UP:
return KeyboardButton::up();
2504 case VK_DOWN:
return KeyboardButton::down();
2505 case VK_LEFT:
return KeyboardButton::left();
2506 case VK_RIGHT:
return KeyboardButton::right();
2513 case VK_TAB:
return KeyboardButton::tab();
2514 case VK_PRIOR:
return KeyboardButton::page_up();
2515 case VK_NEXT:
return KeyboardButton::page_down();
2516 case VK_HOME:
return KeyboardButton::home();
2517 case VK_END:
return KeyboardButton::end();
2518 case VK_F1:
return KeyboardButton::f1();
2519 case VK_F2:
return KeyboardButton::f2();
2520 case VK_F3:
return KeyboardButton::f3();
2521 case VK_F4:
return KeyboardButton::f4();
2522 case VK_F5:
return KeyboardButton::f5();
2523 case VK_F6:
return KeyboardButton::f6();
2524 case VK_F7:
return KeyboardButton::f7();
2525 case VK_F8:
return KeyboardButton::f8();
2526 case VK_F9:
return KeyboardButton::f9();
2527 case VK_F10:
return KeyboardButton::f10();
2528 case VK_F11:
return KeyboardButton::f11();
2529 case VK_F12:
return KeyboardButton::f12();
2530 case VK_INSERT:
return KeyboardButton::insert();
2531 case VK_CAPITAL:
return KeyboardButton::caps_lock();
2532 case VK_NUMLOCK:
return KeyboardButton::num_lock();
2533 case VK_SCROLL:
return KeyboardButton::scroll_lock();
2534 case VK_PAUSE:
return KeyboardButton::pause();
2535 case VK_SNAPSHOT:
return KeyboardButton::print_screen();
2537 case VK_SHIFT:
return KeyboardButton::shift();
2538 case VK_LSHIFT:
return KeyboardButton::lshift();
2539 case VK_RSHIFT:
return KeyboardButton::rshift();
2541 case VK_CONTROL:
return KeyboardButton::control();
2542 case VK_LCONTROL:
return KeyboardButton::lcontrol();
2543 case VK_RCONTROL:
return KeyboardButton::rcontrol();
2545 case VK_MENU:
return KeyboardButton::alt();
2546 case VK_LMENU:
return KeyboardButton::lalt();
2547 case VK_RMENU:
return KeyboardButton::ralt();
2550 int key = MapVirtualKey(wparam, 2);
2551 if (isascii(key) && key != 0) {
2566 return ButtonHandle::none();
2574 lookup_raw_key(LPARAM lparam)
const {
2575 unsigned char vsc = (lparam & 0xff0000) >> 16;
2577 if (lparam & 0x1000000) {
2580 case 28:
return KeyboardButton::enter();
2581 case 29:
return KeyboardButton::rcontrol();
2583 case 55:
return KeyboardButton::print_screen();
2584 case 56:
return KeyboardButton::ralt();
2585 case 69:
return KeyboardButton::num_lock();
2586 case 71:
return KeyboardButton::home();
2587 case 72:
return KeyboardButton::up();
2588 case 73:
return KeyboardButton::page_up();
2589 case 75:
return KeyboardButton::left();
2590 case 77:
return KeyboardButton::right();
2591 case 79:
return KeyboardButton::end();
2592 case 80:
return KeyboardButton::down();
2593 case 81:
return KeyboardButton::page_down();
2594 case 82:
return KeyboardButton::insert();
2595 case 83:
return KeyboardButton::del();
2596 case 91:
return KeyboardButton::lmeta();
2597 case 92:
return KeyboardButton::rmeta();
2598 case 93:
return KeyboardButton::menu();
2604 ButtonHandle::none(),
2605 KeyboardButton::escape(),
2618 KeyboardButton::backspace(),
2619 KeyboardButton::tab(),
2632 KeyboardButton::enter(),
2633 KeyboardButton::lcontrol(),
2646 KeyboardButton::lshift(),
2658 KeyboardButton::rshift(),
2660 KeyboardButton::lalt(),
2661 KeyboardButton::space(),
2662 KeyboardButton::caps_lock(),
2663 KeyboardButton::f1(),
2664 KeyboardButton::f2(),
2665 KeyboardButton::f3(),
2666 KeyboardButton::f4(),
2667 KeyboardButton::f5(),
2668 KeyboardButton::f6(),
2669 KeyboardButton::f7(),
2670 KeyboardButton::f8(),
2671 KeyboardButton::f9(),
2672 KeyboardButton::f10(),
2673 KeyboardButton::pause(),
2674 KeyboardButton::scroll_lock(),
2689 return raw_map[vsc];
2694 case 87:
return KeyboardButton::f11();
2695 case 88:
return KeyboardButton::f12();
2696 default:
return ButtonHandle::none();
2708 get_keyboard_map()
const {
2713 unsigned short ex_vsc[] = {0x57, 0x58,
2714 0x011c, 0x011d, 0x0135, 0x0137, 0x0138, 0x0145, 0x0147, 0x0148, 0x0149, 0x014b, 0x014d, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x015b, 0x015c, 0x015d};
2716 for (
int k = 1; k < 84 + 17; ++k) {
2718 vsc = ex_vsc[k - 84];
2723 UINT lparam = vsc << 16;
2725 if (raw_button == ButtonHandle::none()) {
2731 button = KeyboardButton::pause();
2733 }
else if (vsc >= 0x47 && vsc <= 0x53) {
2735 button = raw_button;
2747 UINT vk = MapVirtualKeyA(vsc, MAPVK_VSC_TO_VK_EX);
2748 button = lookup_key(vk);
2754 int len = GetKeyNameTextW(lparam, text, 256);
2766 void WinGraphicsWindow::
2767 handle_raw_input(HRAWINPUT hraw) {
2774 if (GetRawInputData(hraw, RID_INPUT,
nullptr, &dwSize,
sizeof(RAWINPUTHEADER)) == -1) {
2778 lpb = (LPBYTE)alloca(
sizeof(LPBYTE) * dwSize);
2779 if (lpb ==
nullptr) {
2783 if (GetRawInputData(hraw, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize) {
2787 RAWINPUT *raw = (RAWINPUT *)lpb;
2788 if (raw->header.hDevice == 0) {
2792 for (
size_t i = 1; i < _input_devices.size(); ++i) {
2793 if (_input_device_handle[i] == raw->header.hDevice) {
2797 int adjx = raw->data.mouse.lLastX;
2798 int adjy = raw->data.mouse.lLastY;
2800 if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2801 input->set_pointer_in_window(adjx, adjy);
2803 input->pointer_moved(adjx, adjy);
2806 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
2809 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) {
2812 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) {
2815 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) {
2818 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) {
2821 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) {
2824 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
2827 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
2830 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
2833 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
2843 bool WinGraphicsWindow::
2844 handle_mouse_motion(
int x,
int y) {
2852 void WinGraphicsWindow::
2853 handle_mouse_exit() {
2862 HICON WinGraphicsWindow::
2863 get_icon(
const Filename &filename) {
2865 IconFilenames::iterator fi = _icon_filenames.find(filename);
2866 if (fi != _icon_filenames.end()) {
2867 return (HICON)((*fi).second);
2881 windisplay_cat.warning()
2882 <<
"Could not find icon filename " << filename <<
"\n";
2886 fi = _icon_filenames.find(resolved);
2887 if (fi != _icon_filenames.end()) {
2888 _icon_filenames[filename] = (*fi).second;
2889 return (HICON)((*fi).second);
2894 HANDLE h = LoadImage(
nullptr, os.c_str(),
2895 IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2897 windisplay_cat.warning()
2898 <<
"windows icon filename '" << os <<
"' could not be loaded!!\n";
2901 _icon_filenames[filename] = h;
2902 _icon_filenames[resolved] = h;
2910 HCURSOR WinGraphicsWindow::
2911 get_cursor(
const Filename &filename) {
2913 if (filename.empty()) {
2918 IconFilenames::iterator fi = _cursor_filenames.find(filename);
2919 if (fi != _cursor_filenames.end()) {
2920 return (HCURSOR)((*fi).second);
2930 windisplay_cat.warning()
2931 <<
"Could not find cursor filename " << filename <<
"\n";
2934 fi = _cursor_filenames.find(resolved);
2935 if (fi != _cursor_filenames.end()) {
2936 _cursor_filenames[filename] = (*fi).second;
2937 return (HCURSOR)((*fi).second);
2942 HANDLE h = LoadImage(
nullptr, os.c_str(),
2943 IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
2945 windisplay_cat.warning()
2946 <<
"windows cursor filename '" << os <<
"' could not be loaded!!\n";
2947 show_error_message();
2950 _cursor_filenames[filename] = h;
2951 _cursor_filenames[resolved] = h;
2955 static HCURSOR get_cursor(
const Filename &filename);
2961 const WinGraphicsWindow::WindowClass &WinGraphicsWindow::
2963 WindowClass wcreg(props);
2964 std::wostringstream wclass_name;
2965 wclass_name << L
"WinGraphicsWindow" << _window_class_index;
2966 wcreg._name = wclass_name.str();
2968 std::pair<WindowClasses::iterator, bool> found = _window_classes.insert(wcreg);
2969 const WindowClass &wclass = (*found.first);
2971 if (!found.second) {
2977 _window_class_index++;
2981 HINSTANCE instance = GetModuleHandle(
nullptr);
2984 ZeroMemory(&wc,
sizeof(wc));
2985 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2987 wc.hInstance = instance;
2989 wc.hIcon = wclass._icon;
2991 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
2992 wc.lpszMenuName =
nullptr;
2993 wc.lpszClassName = wclass._name.c_str();
2995 if (!RegisterClassW(&wc)) {
2996 windisplay_cat.error()
2997 <<
"could not register window class " << wclass._name <<
"!" << endl;
3007 WinGraphicsWindow::WinWindowHandle::
3019 void WinGraphicsWindow::WinWindowHandle::
3028 void WinGraphicsWindow::WinWindowHandle::
3029 receive_windows_message(
unsigned int msg,
int wparam,
int lparam) {
3030 if (_window !=
nullptr) {
3037 void PrintErrorMessage(DWORD msgID) {
3038 LPTSTR pMessageBuffer;
3040 if (msgID==PRINT_LAST_ERROR)
3041 msgID=GetLastError();
3043 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
3045 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3046 (LPTSTR) &pMessageBuffer,
3048 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
3049 windisplay_cat.fatal() <<
"System error msg: " << pMessageBuffer << endl;
3050 LocalFree( pMessageBuffer );
3056 if (windisplay_cat.is_debug()) {
3057 windisplay_cat.debug()
3058 <<
"Skipping ClearToBlack, no origin specified yet.\n";
3063 if (windisplay_cat.is_debug()) {
3064 windisplay_cat.debug()
3065 <<
"ClearToBlack(" << hWnd <<
", " << props <<
")\n";
3068 HDC hDC=GetDC(hWnd);
3074 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
3075 ReleaseDC(hWnd,hDC);
3084 GetClientRect(hwnd, view_rect);
3087 ul.x = view_rect->left;
3088 ul.y = view_rect->top;
3089 lr.x = view_rect->right;
3090 lr.y = view_rect->bottom;
3092 ClientToScreen(hwnd, &ul);
3093 ClientToScreen(hwnd, &lr);
3095 view_rect->left = ul.x;
3096 view_rect->top = ul.y;
3097 view_rect->right = lr.x;
3098 view_rect->bottom = lr.y;
3107 nassertv(wnd_proc !=
nullptr);
3116 nassertv(wnd_proc !=
nullptr);
3125 _window_proc_classes.clear();
3142 return callbackData->get_msg() == WM_TOUCH;
3151 return _num_touches;
3160 nassertr(index >= 0 && index < MAX_TOUCHES,
TouchInfo());
3162 TOUCHINPUT ti = _touches[index];
3164 point.x = TOUCH_COORD_TO_PIXEL(ti.x);
3165 point.y = TOUCH_COORD_TO_PIXEL(ti.y);
3166 ScreenToClient(_hWnd, &point);
3171 ret.set_id(ti.dwID);
3172 ret.set_flags(ti.dwFlags);
get_real_time
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
The name of a file, such as a texture file or an Egg file.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
bool resolve_filename(const DSearchPath &searchpath, const std::string &default_extension=std::string())
Searches the given search path for the filename.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
void set_size_and_recalc(int x, int y)
Changes the x_size and y_size, then recalculates structures that depend on size.
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
This specialization on CallbackData is passed when the callback is initiated from from an implementat...
Defines an interface for storing platform-specific window processor methods.
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
get_unexposed_draw
See set_unexposed_draw().
get_properties
Returns the current properties of the window.
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
get_close_request_event
Returns the name of the event set via set_close_request_event().
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
Similar to MutexHolder, but for a light mutex.
This class can be used to convert text between multiple representations, e.g.
std::wstring decode_text(const std::string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system.
get_text
Returns the current text, as encoded via the current encoding system.
void set_wtext(const std::wstring &wtext)
Changes the text that is stored in the encoder.
Stores information for a single touch event.
TypeHandle is the identifier used to differentiate C++ class types.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
This is an abstract base class for wglGraphicsPipe and wdxGraphicsPipe; that is, those graphics pipes...
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
void receive_windows_message(unsigned int msg, int wparam, int lparam)
This is called to receive a keyboard event generated by proxy by another window in a parent process.
virtual bool is_touch_event(GraphicsWindowProcCallbackData *callbackData)
Returns whether the specified event msg is a touch message.
virtual MouseData get_pointer(int device) const
Returns the MouseData associated with the nth input device's pointer.
virtual bool move_pointer(int device, int x, int y)
Forces the pointer to the indicated position within the window, if possible.
virtual LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
This is the nonstatic window_proc function.
virtual int get_num_touches()
Returns the current number of touches on this window.
virtual bool supports_window_procs() const
Returns whether this window supports adding of windows proc handlers.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
virtual void close_ime()
Forces the ime window to close, if any.
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
This is attached to the window class for all WinGraphicsWindow windows; it is called to handle window...
virtual void remove_window_proc(const GraphicsWindowProc *wnd_proc_object)
Removes the specified Windows proc event handler.
virtual TouchInfo get_touch_info(int index)
Returns the TouchInfo object describing the specified touch.
virtual void clear_window_procs()
Removes all Windows proc event handlers.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
virtual void add_window_proc(const GraphicsWindowProc *wnd_proc_object)
Adds the specified Windows proc event handler to be called whenever a Windows event occurs.
This object represents a window on the desktop, not necessarily a Panda window.
virtual void receive_windows_message(unsigned int msg, int wparam, int lparam)
Called on a child handle to deliver a keyboard button event generated in the parent window.
get_os_handle
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
clear_cursor_filename
Removes the cursor_filename specification from the properties.
has_cursor_filename
Returns true if set_cursor_filename() has been specified.
get_title
Returns the window's title.
get_undecorated
Returns true if the window has no border.
clear_cursor_hidden
Removes the cursor_hidden specification from the properties.
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
set_mouse_mode
Specifies the mode in which the window is to operate its mouse pointer.
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
int get_y_origin() const
Returns the y coordinate of the window's top-left corner, not including decorations.
has_undecorated
Returns true if set_undecorated() has been specified.
clear_z_order
Removes the z_order specification from the properties.
get_minimized
Returns true if the window is minimized.
clear_mouse_mode
Removes the mouse_mode specification from the properties.
has_fullscreen
Returns true if set_fullscreen() has been specified.
clear_title
Removes the title specification from the properties.
has_minimized
Returns true if set_minimized() has been specified.
set_size
Specifies the requested size of the window, in pixels.
get_foreground
Returns true if the window is in the foreground.
has_fixed_size
Returns true if set_fixed_size() has been specified.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
clear_fixed_size
Removes the fixed_size specification from the properties.
clear_fullscreen
Removes the fullscreen specification from the properties.
set_foreground
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
set_open
Specifies whether the window should be open.
get_z_order
Returns the window's z_order.
get_icon_filename
Returns the icon filename associated with the window.
get_fullscreen
Returns true if the window is in fullscreen mode.
has_title
Returns true if the window title has been specified, false otherwise.
get_mouse_mode
See set_mouse_mode().
has_origin
Returns true if the window origin has been specified, false otherwise.
has_foreground
Returns true if set_foreground() has been specified.
clear_foreground
Removes the foreground specification from the properties.
get_cursor_filename
Returns the icon filename associated with the mouse cursor.
clear_undecorated
Removes the undecorated specification from the properties.
get_cursor_hidden
Returns true if the mouse cursor is invisible.
clear_minimized
Removes the minimized specification from the properties.
has_cursor_hidden
Returns true if set_cursor_hidden() has been specified.
set_minimized
Specifies whether the window should be created minimized (true), or normal (false).
clear_icon_filename
Removes the icon_filename specification from the properties.
has_z_order
Returns true if the window z_order has been specified, false otherwise.
get_fixed_size
Returns true if the window cannot be resized by the user, false otherwise.
int get_x_origin() const
Returns the x coordinate of the window's top-left corner, not including decorations.
set_origin
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
has_icon_filename
Returns true if set_icon_filename() has been specified.
This is our own Panda specialization on the default STL map.
This is our own Panda specialization on the default STL set.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BEGIN_PUBLISH typedef PointerData MouseData
Deprecated alias for PointerData.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void get_client_rect_screen(HWND hwnd, RECT *view_rect)
Fills view_rect with the coordinates of the client area of the indicated window, converted to screen ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.