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