Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
vpWin32Window.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Windows 32 display's window class
32  */
33 
34 #include <iostream>
35 #include <visp3/core/vpConfig.h>
36 #include <visp3/gui/vpWin32API.h>
37 
38 #if (defined(VISP_HAVE_GDI) || defined(VISP_HAVE_D3D9))
39 
40 #define MAX_SEM_COUNT 2147483647
41 
42 #ifndef DOXYGEN_SHOULD_SKIP_THIS
43 
44 #include <visp3/gui/vpWin32Window.h>
45 
46 BEGIN_VISP_NAMESPACE
47 
48 // Should be already defined ...
49 #ifndef GET_X_LPARAM
50 #define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
51 #endif
52 
53 #ifndef GET_Y_LPARAM
54 #define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
55 #endif
56 
57 // declares the window as thread local
58 // allows multiple displays
59 #ifdef __MINGW32__
60 __thread vpWin32Window *window;
61 #else
62 __declspec(thread) vpWin32Window *window;
63 #endif
64 
65 bool vpWin32Window::registered = false;
69 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
70 {
71  // the first time this callback is executed, put the window in initialized
72  // state
73  if (window != nullptr) {
74  if (!window->isInitialized()) {
75  window->initialized = true;
76  vpReleaseSemaphore(window->semaInit, 1, nullptr);
77  }
78  }
79  switch (message) {
80  case vpWM_DISPLAY:
81  // redraw the whole window
82  InvalidateRect(window->getHWnd(), nullptr, TRUE);
83  UpdateWindow(window->getHWnd());
84  break;
85 
86  case vpWM_DISPLAY_ROI: {
87  RECT rect;
88 
89  rect.left = LOWORD(wParam);
90  rect.right = HIWORD(wParam);
91 
92  rect.top = LOWORD(lParam);
93  rect.bottom = HIWORD(lParam);
94 
95  InvalidateRect(window->getHWnd(), &rect, TRUE);
96  UpdateWindow(window->getHWnd());
97  } break;
98 
99  case WM_LBUTTONDOWN: {
100  window->clickX = GET_X_LPARAM(lParam);
101  window->clickY = GET_Y_LPARAM(lParam);
102 
103  window->clickButton = vpMouseButton::button1;
104  vpReleaseSemaphore(window->semaClick, 1, nullptr);
105  } break;
106 
107  case WM_MBUTTONDOWN: {
108  window->clickX = GET_X_LPARAM(lParam);
109  window->clickY = GET_Y_LPARAM(lParam);
110 
111  window->clickButton = vpMouseButton::button2;
112  vpReleaseSemaphore(window->semaClick, 1, nullptr);
113  } break;
114 
115  case WM_RBUTTONDOWN: {
116  window->clickX = GET_X_LPARAM(lParam);
117  window->clickY = GET_Y_LPARAM(lParam);
118 
119  window->clickButton = vpMouseButton::button3;
120  vpReleaseSemaphore(window->semaClick, 1, nullptr);
121  } break;
122 
123  case WM_LBUTTONUP: {
124  window->clickXUp = GET_X_LPARAM(lParam);
125  window->clickYUp = GET_Y_LPARAM(lParam);
126 
127  window->clickButtonUp = vpMouseButton::button1;
128  vpReleaseSemaphore(window->semaClickUp, 1, nullptr);
129  } break;
130 
131  case WM_MBUTTONUP: {
132  window->clickXUp = GET_X_LPARAM(lParam);
133  window->clickYUp = GET_Y_LPARAM(lParam);
134 
135  window->clickButtonUp = vpMouseButton::button2;
136  vpReleaseSemaphore(window->semaClickUp, 1, nullptr);
137  } break;
138 
139  case WM_RBUTTONUP: {
140  window->clickXUp = GET_X_LPARAM(lParam);
141  window->clickYUp = GET_Y_LPARAM(lParam);
142 
143  window->clickButtonUp = vpMouseButton::button3;
144  vpReleaseSemaphore(window->semaClickUp, 1, nullptr);
145  } break;
146  case WM_MOUSEMOVE: {
147  window->coordX = GET_X_LPARAM(lParam);
148  window->coordY = GET_Y_LPARAM(lParam);
149  vpReleaseSemaphore(window->semaMove, 1, nullptr);
150  } break;
151 
152  case WM_SYSKEYDOWN:
153  // case WM_SYSKEYUP:
154  case WM_KEYDOWN:
155  // case WM_KEYUP:
156  {
157  GetKeyNameText((LONG)lParam, window->lpString,
158  10); // 10 is the size of lpString
159  // window->key = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR);
160  vpReleaseSemaphore(window->semaKey, 1, nullptr);
161  break;
162  }
163 
164  case WM_COMMAND:
165 
166  break;
167 
168  // we must prevent the window from erasing the background each time a
169  // repaint is needed
170  case WM_ERASEBKGND:
171  return (LRESULT)1;
172 
173  case WM_PAINT:
174  // render the display
175  window->renderer->render();
176  break;
177 
178  case vpWM_CLOSEDISPLAY:
179  // cleanup code here, if needed
180  // destroys the window
181  DestroyWindow(hWnd);
182  break;
183 
184  case WM_DESTROY:
185  PostQuitMessage(0);
186  break;
187  default:
188  return DefWindowProc(hWnd, message, wParam, lParam);
189  }
190  return 0;
191 }
192 
196 vpWin32Window::vpWin32Window(vpWin32Renderer *rend) : initialized(false)
197 {
198  renderer = rend;
199 
200  // registered is static member class and is initialized at the beginning of
201  // this file (registered = false)
202 
203  // creates the semaphores
204  semaInit = CreateSemaphore(nullptr, 0, 1, nullptr);
205  semaClick = CreateSemaphore(nullptr, 0, MAX_SEM_COUNT, nullptr);
206  semaClickUp = CreateSemaphore(nullptr, 0, MAX_SEM_COUNT, nullptr);
207  semaKey = CreateSemaphore(nullptr, 0, MAX_SEM_COUNT, nullptr);
208  semaMove = CreateSemaphore(nullptr, 0, MAX_SEM_COUNT, nullptr);
209 }
210 
214 vpWin32Window::~vpWin32Window()
215 {
216  delete renderer;
217  CloseHandle(semaInit);
218  CloseHandle(semaClick);
219  CloseHandle(semaClickUp);
220  CloseHandle(semaKey);
221  CloseHandle(semaMove);
222 }
223 
234 void vpWin32Window::initWindow(const char *title, int posx, int posy, unsigned int w, unsigned int h)
235 {
236  // the window's style
237  DWORD style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
238  const char g_szClassName[] = "ViSPWindowClass";
239 
240  RECT rect;
241  rect.left = 0;
242  rect.right = static_cast<int>(w);
243  rect.top = 0;
244  rect.bottom = static_cast<int>(h);
245 
246  // now we register the window's class
247  WNDCLASSEX wcex;
248 
249  wcex.cbSize = sizeof(WNDCLASSEX);
250 
251  wcex.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
252  wcex.lpfnWndProc = (WNDPROC)WndProc;
253  wcex.cbClsExtra = 0;
254  wcex.cbWndExtra = 0;
255  wcex.hInstance = hInst;
256  wcex.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
257  wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
258  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
259  wcex.lpszMenuName = nullptr;
260  wcex.lpszClassName = g_szClassName;
261  wcex.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
262 
263  RegisterClassEx(&wcex);
264 
265  AdjustWindowRectEx(&rect, style, false, style);
266  // std::cout << "win client size (orig)(w,h): " << rect.left << " " <<
267  // rect.top << " " << rect.right << " " << rect.bottom << std::endl;
268 
269  // creates the window
270  hWnd = CreateWindowEx(WS_EX_APPWINDOW, g_szClassName, title, style, posx, posy, rect.right - rect.left,
271  rect.bottom - rect.top, nullptr, nullptr, hInst, nullptr);
272  if (hWnd == nullptr) {
273  DWORD err = GetLastError();
274  std::cout << "err CreateWindowEx=" << err << std::endl;
275  throw vpDisplayException(vpDisplayException::cannotOpenWindowError, "Can't create the window!");
276  }
277  SetWindowPos(hWnd, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE);
278 
279  // needed if we want to access it from the callback method (message handler)
280  window = this;
281 
282  // initialize the renderer
283  renderer->init(hWnd, w, h);
284 
285  // displays the window
286  ShowWindow(hWnd, SW_SHOWDEFAULT);
287  // ShowWindow(hWnd, SW_SHOW);
288  UpdateWindow(hWnd);
289 
290  MSG msg;
291 
292  // starts the message loop
293  while (true) {
294  BOOL val = GetMessage(&msg, nullptr, 0, 0);
295  if (val == -1) {
296  std::cout << "GetMessage error:" << GetLastError() << std::endl;
297  break;
298  }
299  else if (val == 0) {
300  break;
301  }
302  else {
303  if (!TranslateAccelerator(msg.hwnd, nullptr, &msg)) {
304  TranslateMessage(&msg);
305  DispatchMessage(&msg);
306  }
307  }
308  }
309 }
310 
311 END_VISP_NAMESPACE
312 
313 #endif
314 #elif !defined(VISP_BUILD_SHARED_LIBS)
315 // Work around to avoid warning: libvisp_gui.a(vpWin32Window.cpp.o) has no symbols
316 void dummy_vpWin32Window() { };
317 #endif
Error that can be emitted by the vpDisplay class and its derivatives.
@ cannotOpenWindowError
Unable to open display window.