NTrace
GPU ray tracing framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Window.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2011, NVIDIA Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA Corporation nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "gui/Window.hpp"
29 #include "gui/Image.hpp"
30 #include "gpu/GLContext.hpp"
31 #include "base/Thread.hpp"
32 
33 #include <commdlg.h>
34 #include <ShlObj.h>
35 #include <ShellAPI.h>
36 
37 using namespace FW;
38 
39 //------------------------------------------------------------------------
40 
41 static const char* const s_defaultTitle = "Anonymous window";
42 static const Vec2i s_defaultSize = Vec2i(1024, 768);
43 static bool s_defaultFullScreen = false;
44 static const char* const s_windowClassName = "FrameworkWindowClass";
45 
46 //------------------------------------------------------------------------
47 
48 bool Window::s_inited = false;
49 Array<Window*>* Window::s_open = NULL;
50 bool Window::s_ignoreRepaint = false;
51 
52 //------------------------------------------------------------------------
53 
55 : m_glConfigDirty (false),
56  m_gl (NULL),
57 
58  m_isRealized (false),
59  m_isVisible (true),
60  m_enablePaste (false),
61 
62  m_title (s_defaultTitle),
63  m_isFullScreen (false),
64  m_pendingSize (-1),
65 
66  m_pendingKeyFlush (false),
67 
68  m_mouseKnown (false),
69  m_mousePos (0),
70  m_mouseDragCount (0),
71  m_mouseWheelAcc (0),
72 
73  m_prevSize (-1)
74 {
75  create();
76  setSize(s_defaultSize);
77  setFullScreen(s_defaultFullScreen);
78 
79  FW_ASSERT(s_open);
80  s_open->add(this);
81 }
82 
83 //------------------------------------------------------------------------
84 
86 {
87  destroy();
88 
89  FW_ASSERT(s_open);
90  s_open->removeItem(this);
91 }
92 
93 //------------------------------------------------------------------------
94 
95 void Window::setTitle(const String& title)
96 {
97  if (m_title != title)
98  {
99  m_title = title;
100  SetWindowText(m_hwnd, title.getPtr());
101  }
102 }
103 
104 //------------------------------------------------------------------------
105 
107 {
108  FW_ASSERT(size.x >= 0 && size.y >= 0);
109 
110  if (m_isFullScreen)
111  {
112  m_pendingSize = size;
113  return;
114  }
115 
116  RECT rc;
117  rc.left = 0;
118  rc.top = 0;
119  rc.right = size.x;
120  rc.bottom = size.y;
121  AdjustWindowRect(&rc, GetWindowLong(m_hwnd, GWL_STYLE), (GetMenu(m_hwnd) != NULL));
122 
123  SetWindowPos(m_hwnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top,
124  SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER);
125 }
126 
127 //------------------------------------------------------------------------
128 
130 {
131  RECT rect;
132  GetClientRect(m_hwnd, &rect);
133  return Vec2i(rect.right, rect.bottom);
134 }
135 
136 //------------------------------------------------------------------------
137 
138 void Window::setVisible(bool visible)
139 {
140  if (m_isRealized && m_isVisible != visible)
141  ShowWindow(m_hwnd, (visible) ? SW_SHOW : SW_HIDE);
142  m_isVisible = visible;
143 }
144 
145 //------------------------------------------------------------------------
146 
147 void Window::setFullScreen(bool isFull)
148 {
149  if (m_isFullScreen == isFull)
150  return;
151 
152  m_isFullScreen = isFull;
153  if (isFull)
154  {
155  RECT desk;
156  m_origStyle = GetWindowLong(m_hwnd, GWL_STYLE);
157  GetWindowRect(m_hwnd, &m_origRect);
158  GetWindowRect(GetDesktopWindow(), &desk);
159  setWindowLong(m_hwnd, GWL_STYLE, (m_origStyle & ~WS_OVERLAPPEDWINDOW) | WS_POPUP);
160  SetWindowPos(m_hwnd, HWND_TOP,
161  desk.left, desk.top, desk.right - desk.left, desk.bottom - desk.top,
162  SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER);
163  }
164  else
165  {
166  setWindowLong(m_hwnd, GWL_STYLE, m_origStyle);
167  SetWindowPos(m_hwnd, NULL,
168  m_origRect.left,
169  m_origRect.top,
170  m_origRect.right - m_origRect.left,
171  m_origRect.bottom - m_origRect.top,
172  SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER);
173 
174  if (m_pendingSize.x != -1)
175  {
176  setSize(m_pendingSize);
177  m_pendingSize = -1;
178  }
179  }
180 }
181 
182 //------------------------------------------------------------------------
183 
184 void Window::realize(void)
185 {
186  if (!m_isRealized)
187  {
188  ShowWindow(m_hwnd, (m_isVisible) ? SW_SHOW : SW_HIDE);
189  m_isRealized = true;
190  }
191 }
192 
193 //------------------------------------------------------------------------
194 
196 {
197  m_glConfig = config;
198  m_glConfigDirty = (m_gl && memcmp(&m_glConfig, &m_gl->getConfig(), sizeof(GLContext::Config)) != 0);
199 }
200 
201 //------------------------------------------------------------------------
202 
204 {
205  if (!m_gl)
206  {
207  m_gl = new GLContext(m_hdc, m_glConfig);
208  m_gl->setView(0, getSize());
209  }
210  m_gl->makeCurrent();
211  return m_gl;
212 }
213 
214 //------------------------------------------------------------------------
215 
216 void Window::repaint(void)
217 {
218  InvalidateRect(m_hwnd, NULL, false);
219 }
220 
221 //------------------------------------------------------------------------
222 
224 {
225  if (s_ignoreRepaint)
226  return;
227  s_ignoreRepaint = true;
228 
229  if (m_glConfigDirty)
230  {
231  m_glConfigDirty = false;
232  recreate();
233  }
234 
235  Vec2i size = getSize();
236  if (size.x > 0 && size.y > 0)
237  {
238  getGL()->setView(0, size);
239  if (!getDiscardEvents())
240  {
241  s_ignoreRepaint = false;
242  if (m_prevSize != size)
243  {
244  m_prevSize = size;
245  postEvent(createSimpleEvent(EventType_Resize));
246  }
247  postEvent(createSimpleEvent(EventType_PrePaint));
248  postEvent(createSimpleEvent(EventType_Paint));
249  postEvent(createSimpleEvent(EventType_PostPaint));
250  s_ignoreRepaint = true;
251  }
252  getGL()->swapBuffers();
253  }
254 
255  Thread::yield();
256  s_ignoreRepaint = false;
257 }
258 
259 //------------------------------------------------------------------------
260 
262 {
263  PostMessage(m_hwnd, WM_CLOSE, 0, 0);
264 }
265 
266 //------------------------------------------------------------------------
267 
268 void Window::enableDrop(bool enable)
269 {
270  DragAcceptFiles(m_hwnd, enable);
271 }
272 
273 //------------------------------------------------------------------------
274 
275 void Window::enablePaste(bool enable)
276 {
277  m_enablePaste = enable;
278 }
279 
280 //------------------------------------------------------------------------
281 
283 {
284  if (!listener || m_listeners.contains(listener))
285  return;
286 
287  m_listeners.add(listener);
288  listener->handleEvent(createSimpleEvent(EventType_AddListener));
289 }
290 
291 //------------------------------------------------------------------------
292 
294 {
295  if (!m_listeners.contains(listener))
296  return;
297 
298  m_listeners.removeItem(listener);
299  listener->handleEvent(createSimpleEvent(EventType_RemoveListener));
300 }
301 
302 //------------------------------------------------------------------------
303 
305 {
306  while (m_listeners.getSize())
307  removeListener(m_listeners.getLast());
308 }
309 
310 //------------------------------------------------------------------------
311 
312 void Window::showMessageDialog(const String& title, const String& text)
313 {
314  bool old = setDiscardEvents(true);
315  MessageBox(m_hwnd, text.getPtr(), title.getPtr(), MB_OK);
316  setDiscardEvents(old);
317 }
318 
319 //------------------------------------------------------------------------
320 
321 String Window::showFileDialog(const String& title, bool save, const String& filters, const String& initialDir, bool forceInitialDir)
322 {
323  // Form the filter string.
324 
325  String filterStr;
326  Array<String> extensions;
327  int numFilters = 0;
328  int start = 0;
329 
330  while (start < filters.getLength())
331  {
332  int colon = filters.indexOf(':', start);
333  FW_ASSERT(colon != -1);
334  int comma = filters.indexOf(',', colon);
335  if (comma == -1)
336  comma = filters.getLength();
337  FW_ASSERT(colon < comma);
338 
339  String all;
340  while (start < colon)
341  {
342  int semi = filters.indexOf(';', start);
343  if (semi == -1 || semi > colon)
344  semi = colon;
345 
346  String ext = filters.substring(start, semi);
347  extensions.add(ext);
348  start = semi + 1;
349 
350  if (all.getLength())
351  all += ';';
352  all += "*.";
353  all += ext;
354  }
355 
356  String title = filters.substring(colon + 1, comma);
357  filterStr.appendf("%s Files (%s)\n%s\n", title.getPtr(), all.getPtr(), all.getPtr());
358  numFilters++;
359  start = comma + 1;
360  }
361 
362  // Add "All Supported Formats" and "All Files".
363 
364  if (numFilters > 1 && !save)
365  {
366  String all;
367  for (int i = 0; i < extensions.getSize(); i++)
368  {
369  if (all.getLength())
370  all += ';';
371  all += "*.";
372  all += extensions[i];
373  }
374  filterStr = sprintf("All Supported Formats (%s)\n%s\n", all.getPtr(), all.getPtr()) + filterStr;
375  }
376  filterStr += "All Files (*.*)\n*.*\n";
377 
378  // Convert linefeeds to null characters.
379 
380  Array<char> filterChars(filterStr.getPtr(), filterStr.getLength() + 1);
381  for (int i = 0; i < filterChars.getSize(); i++)
382  if (filterChars[i] == '\n')
383  filterChars[i] = '\0';
384 
385  // Setup OPENFILENAME struct.
386 
387  char rawPath[MAX_PATH];
388  rawPath[0] = '\0';
389 
390  U32 flags;
391  if (save)
392  flags = OFN_CREATEPROMPT | OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
393  else
394  flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
395 
396  OPENFILENAME ofn;
397  ofn.lStructSize = sizeof(ofn);
398  ofn.hwndOwner = m_hwnd;
399  ofn.hInstance = NULL;
400  ofn.lpstrFilter = filterChars.getPtr();
401  ofn.lpstrCustomFilter = NULL;
402  ofn.nMaxCustFilter = 0;
403  ofn.nFilterIndex = 0;
404  ofn.lpstrFile = rawPath;
405  ofn.nMaxFile = FW_ARRAY_SIZE(rawPath);
406  ofn.lpstrFileTitle = NULL;
407  ofn.nMaxFileTitle = 0;
408  ofn.lpstrInitialDir = (initialDir.getLength() && forceInitialDir) ? initialDir.getPtr() : NULL;
409  ofn.lpstrTitle = title.getPtr();
410  ofn.Flags = flags;
411  ofn.nFileOffset = 0;
412  ofn.nFileExtension = 0;
413  ofn.lpstrDefExt = (extensions.getSize()) ? extensions[0].getPtr() : NULL;
414  ofn.lCustData = NULL;
415  ofn.lpfnHook = NULL;
416  ofn.lpTemplateName = NULL;
417  ofn.pvReserved = NULL;
418  ofn.dwReserved = 0;
419  ofn.FlagsEx = 0;
420 
421  // Backup current working directory and set it to initialDir.
422 
423  char oldCwd[MAX_PATH];
424  bool oldCwdValid = (GetCurrentDirectory(FW_ARRAY_SIZE(oldCwd), oldCwd) != 0);
425  if (oldCwdValid && initialDir.getLength() && !forceInitialDir)
426  SetCurrentDirectory(initialDir.getPtr());
427 
428  // Show modal dialog.
429 
430  bool old = setDiscardEvents(true);
431  bool rawPathValid = (((save) ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) != 0);
432  setDiscardEvents(old);
433  getGL()->swapBuffers();
434 
435  // Convert path to absolute and restore current working directory.
436 
437  char absolutePath[MAX_PATH];
438  bool absolutePathValid = (rawPathValid && GetFullPathName(rawPath, FW_ARRAY_SIZE(absolutePath), absolutePath, NULL) != 0);
439  if (oldCwdValid)
440  SetCurrentDirectory(oldCwd);
441 
442  // Convert path to relative.
443 
444  char relativePath[MAX_PATH];
445  bool relativePathValid = (oldCwdValid && absolutePathValid &&
446  PathRelativePathTo(relativePath, oldCwd, FILE_ATTRIBUTE_DIRECTORY, (absolutePathValid) ? absolutePath : rawPath, 0));
447 
448  // Return the best path that we have.
449 
450  return (relativePathValid) ? relativePath : (absolutePathValid) ? absolutePath : (rawPathValid) ? rawPath : "";
451 }
452 
453 //------------------------------------------------------------------------
454 
455 Array<String> Window::showDirLoadDialog(const String& title, const String& initialDir)
456 {
457  char rawPath[MAX_PATH];
458  rawPath[0] = '\0';
459  Array<String> names;
460 
461  LPITEMIDLIST pidl = NULL;
462  BROWSEINFO bi = { 0 };
463 
464  bi.hwndOwner = m_hwnd;
465  bi.pszDisplayName = rawPath;
466  bi.pidlRoot = NULL;
467  bi.lpszTitle = title.getPtr();
468  bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI;
469 
470  bool old = setDiscardEvents(true);
471  if((pidl = SHBrowseForFolder(&bi)) != NULL)
472  {
473  SHGetPathFromIDList(pidl, rawPath);
474  CoTaskMemFree(pidl);
475 
476  names.add(String(rawPath));
477  traverseDirectory(rawPath, names);
478  }
479  setDiscardEvents(old);
480  getGL()->swapBuffers();
481 
482  return names;
483 }
484 
485 //------------------------------------------------------------------------
486 
488 {
489  if (!m_isRealized || !m_isVisible)
490  return;
491 
492  GLContext* gl = getGL();
493  for (int i = 0; i < 3; i++)
494  {
495  gl->drawModalMessage(msg);
496  gl->swapBuffers();
497  }
498 }
499 
500 //------------------------------------------------------------------------
501 
503 {
504  if (s_inited)
505  return;
506  s_inited = true;
507 
508  // Register window class.
509 
510  WNDCLASS wc;
511  wc.style = 0;
512  wc.lpfnWndProc = DefWindowProc;
513  wc.cbClsExtra = 0;
514  wc.cbWndExtra = 0;
515  wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
516  wc.hIcon = LoadIcon(wc.hInstance, MAKEINTRESOURCE(101));
517  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
518  wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
519  wc.lpszMenuName = NULL;
520  wc.lpszClassName = s_windowClassName;
521 
522  if (!wc.hIcon)
523  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
524 
525  RegisterClass(&wc);
526 
527  // Create list of open windows.
528 
529  FW_ASSERT(!s_open);
530  s_open = new Array<Window*>;
531 }
532 
533 //------------------------------------------------------------------------
534 
536 {
537  if (!s_inited)
538  return;
539  s_inited = false;
540 
541  FW_ASSERT(s_open);
542  while (s_open->getSize())
543  delete s_open->getLast();
544  delete s_open;
545  s_open = NULL;
546 }
547 
548 //------------------------------------------------------------------------
549 
551 {
552  staticInit();
553  FW_ASSERT(s_open);
554 
555  HWND hwnd = CreateWindow(
556  s_windowClassName,
557  s_defaultTitle,
558  WS_OVERLAPPEDWINDOW,
559  1, 1, 0, 0,
560  NULL,
561  NULL,
562  (HINSTANCE)GetModuleHandle(NULL),
563  NULL);
564 
565  if (!hwnd)
566  failWin32Error("CreateWindow");
567 
568  return hwnd;
569 }
570 
571 //------------------------------------------------------------------------
572 
573 UPTR Window::setWindowLong(HWND hwnd, int idx, UPTR value)
574 {
575 #if FW_64
576  return (UPTR)SetWindowLongPtr(hwnd, idx, (LONG_PTR)value);
577 #else
578  return (UPTR)SetWindowLong(hwnd, idx, (LONG)value);
579 #endif
580 }
581 
582 //------------------------------------------------------------------------
583 
585 {
586  if (s_inited)
587  for (int i = 0; i < s_open->getSize(); i++)
588  s_open->get(i)->realize();
589 }
590 
591 //------------------------------------------------------------------------
592 
594 {
595  bool old = setDiscardEvents(true);
596 
597  MSG msg;
598  while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
599  {
600  TranslateMessage(&msg);
601  DispatchMessage(&msg);
602  }
603 
604  setDiscardEvents(old);
605 }
606 
607 //------------------------------------------------------------------------
608 
609 void Window::traverseDirectory(const char *root, Array<String> &names)
610 {
611  HANDLE h;
612  BOOL ok;
613  WIN32_FIND_DATA fd;
614 
615  int error;
616  char start[MAX_PATH + 1];
617  char dir[MAX_PATH + 1];
618 
619  strcpy_s(start, root);
620  strcat_s(start, "/*");
621 
622  for(h = FindFirstFile(start, &fd), ok = 1; h != INVALID_HANDLE_VALUE && ok; ok = FindNextFile(h, &fd))
623  {
624  if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
625  {
626  strcpy_s(dir, fd.cFileName);
627  if((strcmp(dir,".") != 0) && (strcmp(dir,"..") != 0)) // Recurse into subdirectories
628  {
629  strcpy_s(start, root);
630  strcat_s(start, "/");
631  strcat_s(start, dir);
632  traverseDirectory(start, names);
633  }
634  }
635  else
636  {
637  String lower = String(fd.cFileName).toLower();
638  if(lower.endsWith(".bin") || lower.endsWith(".obj")) // Find a model file possibly use the supported file description
639  {
640  strcpy_s(start, root);
641  strcat_s(start, "/");
642  strcat_s(start, fd.cFileName);
643  names.add(String(start));
644  }
645  }
646  }
647 
648  error = GetLastError();
649  if(error != ERROR_NO_MORE_FILES)
650  failWin32Error("Opening directory");
651 
652  if(h != INVALID_HANDLE_VALUE)
653  {
654  ok = FindClose(h);
655  }
656 }
657 
658 //------------------------------------------------------------------------
659 
660 Window::Event Window::createFileEvent(EventType type, HANDLE hDrop)
661 {
662  Event ev = createSimpleEvent(type);
663  for(int idx = 0; ; idx++)
664  {
665  int len = DragQueryFile((HDROP)hDrop, idx, 0, 0);
666  if (!len)
667  break;
668  char* buf = new char[len+1];
669  DragQueryFile((HDROP)hDrop, idx, buf, len+1);
670  ev.files.add(String(buf));
671  delete[] buf;
672  }
673  return ev;
674 }
675 
676 //------------------------------------------------------------------------
677 
678 Window::Event Window::createGenericEvent(EventType type, const String& key, S32 chr, bool mouseKnown, const Vec2i& mousePos)
679 {
680  Event ev;
681  ev.type = type;
682  ev.key = key;
683  ev.keyUnicode = keyToUnicode(key);
684  ev.chr = chr;
685  ev.mouseKnown = mouseKnown;
686  ev.mousePos = mousePos;
687  ev.mouseDelta = (mouseKnown && m_mouseKnown) ? mousePos - m_mousePos : 0;
688  ev.mouseDragging = isMouseDragging();
689  ev.image = NULL;
690  ev.window = this;
691  return ev;
692 }
693 
694 //------------------------------------------------------------------------
695 
696 void Window::postEvent(const Event& ev)
697 {
698  m_mouseKnown = ev.mouseKnown;
699  m_mousePos = ev.mousePos;
700 
701  if (ev.type == EventType_KeyDown ||
702  ev.type == EventType_KeyUp ||
703  ev.type == EventType_Char ||
704  ev.type == EventType_Mouse)
705  {
706  for (int i = m_listeners.getSize() - 1; i >= 0; i--)
707  if (hasError() || m_listeners[i]->handleEvent(ev))
708  break;
709  }
710  else
711  {
712  for (int i = 0; i < m_listeners.getSize(); i++)
713  if (hasError() || m_listeners[i]->handleEvent(ev))
714  break;
715  }
716 
717  if (ev.image)
718  delete ev.image;
719 
720  failIfError();
721 }
722 
723 //------------------------------------------------------------------------
724 
725 void Window::create(void)
726 {
727  m_hwnd = createHWND();
728  m_hdc = GetDC(m_hwnd);
729  if (!m_hdc)
730  failWin32Error("GetDC");
731 
732  setWindowLong(m_hwnd, GWLP_USERDATA, (UPTR)this);
733  setWindowLong(m_hwnd, GWLP_WNDPROC, (UPTR)staticWindowProc);
734 }
735 
736 //------------------------------------------------------------------------
737 
738 void Window::destroy(void)
739 {
740  delete m_gl;
741  setWindowLong(m_hwnd, GWLP_WNDPROC, (UPTR)DefWindowProc);
742  ReleaseDC(m_hwnd, m_hdc);
743  DestroyWindow(m_hwnd);
744 
745  m_gl = NULL;
746  m_hdc = NULL;
747  m_hwnd = NULL;
748 }
749 
750 //------------------------------------------------------------------------
751 
752 void Window::recreate(void)
753 {
754  // Backup properties.
755 
756  RECT rect;
757  GetWindowRect(m_hwnd, &rect);
758  DWORD style = GetWindowLong(m_hwnd, GWL_STYLE);
759 
760  // Recreate.
761 
762  destroy();
763  create();
764 
765  // Restore properties.
766 
767  SetWindowText(m_hwnd, m_title.getPtr());
768  setWindowLong(m_hwnd, GWL_STYLE, style);
769  SetWindowPos(m_hwnd, HWND_TOP, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 0);
770  if (m_isRealized)
771  ShowWindow(m_hwnd, (m_isVisible) ? SW_SHOW : SW_HIDE);
772 }
773 
774 //------------------------------------------------------------------------
775 
776 LRESULT CALLBACK Window::staticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
777 {
778  incNestingLevel(1);
779  Window* win = (Window*)(LONG_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
780  LRESULT res = win->windowProc(uMsg, wParam, lParam);
781  incNestingLevel(-1);
782  return res;
783 }
784 
785 //------------------------------------------------------------------------
786 
787 LRESULT Window::windowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
788 {
789  if (uMsg == WM_ACTIVATE || getDiscardEvents())
790  {
791  if (m_mouseDragCount)
792  ReleaseCapture();
793 
794  m_pendingKeyFlush = true;
795  m_mouseKnown = false;
796  m_mouseDragCount = 0;
797  m_mouseWheelAcc = 0;
798  }
799 
800  if (m_pendingKeyFlush && !getDiscardEvents())
801  {
802  m_pendingKeyFlush = false;
803  for (int slot = m_keysDown.firstSlot(); slot != -1; slot = m_keysDown.nextSlot(slot))
804  postEvent(createKeyEvent(false, m_keysDown.getSlot(slot)));
805  m_keysDown.clear();
806  }
807 
808  if (uMsg == WM_ERASEBKGND)
809  return 0;
810 
811  if (uMsg == WM_PAINT)
812  {
813  PAINTSTRUCT paint;
814  BeginPaint(m_hwnd, &paint);
815  EndPaint(m_hwnd, &paint);
816  repaintNow();
817  return 0;
818  }
819 
820  if (getDiscardEvents())
821  return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
822 
823  switch (uMsg)
824  {
825  case WM_CLOSE:
826  postEvent(createSimpleEvent(EventType_Close));
827  return 0;
828 
829  case WM_KEYDOWN:
830  case WM_KEYUP:
831  case WM_SYSKEYDOWN:
832  case WM_SYSKEYUP:
833  {
834  // Paste.
835 
836  if (m_enablePaste && uMsg == WM_KEYDOWN)
837  {
838  if ((wParam == 'V' && GetKeyState(VK_CONTROL) < 0) ||
839  (wParam == VK_INSERT && GetKeyState(VK_SHIFT) < 0))
840  {
841  if (OpenClipboard(m_hwnd))
842  {
843  if (IsClipboardFormatAvailable(CF_HDROP))
844  {
845  postEvent(createFileEvent(EventType_PasteFiles, (HDROP)GetClipboardData(CF_HDROP)));
846  }
847  else if (IsClipboardFormatAvailable(CF_DIB))
848  {
849  BITMAPINFO* bminfo = (BITMAPINFO*)GetClipboardData(CF_DIB);
850  BITMAPINFOHEADER& hdr = bminfo->bmiHeader;
851  Vec2i size(hdr.biWidth, hdr.biHeight);
852  bool flip = (size.y < 0);
853  if (flip)
854  size.y = -size.y;
855  U8* p = (U8*)bminfo->bmiColors;
856  Image* img = 0;
857  if (hdr.biCompression == 0)
858  {
859  if (hdr.biBitCount == 24)
860  {
861  // set alpha to 255
862  img = new Image(size);
863  for (int y=0; y < size.y; y++, p = (U8*)(((U64)p + 3) & ~(U64)3))
864  for (int x=0; x < size.x; x++, p += 3)
865  img->setABGR(Vec2i(x, flip ? y : (size.y - y - 1)), (p[0] << 16) | (p[1] << 8) | p[2] | 0xff000000u);
866  } else if (hdr.biBitCount == 32)
867  {
868  // untested
869  img = new Image(size);
870  for (int y=0; y < size.y; y++)
871  for (int x=0; x < size.x; x++, p += 4)
872  img->setABGR(Vec2i(x, flip ? y : (size.y - y - 1)), (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
873  }
874  }
875  if (img)
876  {
877  Event ev = createSimpleEvent(EventType_PasteImage);
878  ev.image = img;
879  postEvent(ev);
880  }
881  }
882  CloseClipboard();
883  }
884  return 0;
885  }
886  }
887 
888  // Post key event.
889 
890  bool down = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN);
891  String key = vkeyToKey((U32)wParam);
892  if (key.getLength())
893  {
894  postEvent(createKeyEvent(down, key));
895  if (down && !m_keysDown.contains(key))
896  m_keysDown.add(key);
897  else if (!down && m_keysDown.contains(key))
898  m_keysDown.remove(key);
899  }
900 
901  // Post character events.
902 
903  BYTE keyState[256];
904  GetKeyboardState(keyState);
905 
906  WCHAR buf[256];
907  int num = ToUnicode(
908  (U32)wParam,
909  (((U32)lParam >> 16) & 0xff) | ((down) ? 0 : 0x8000),
910  keyState,
911  buf,
912  FW_ARRAY_SIZE(buf),
913  0);
914 
915  for (int i = 0; i < num; i++)
916  postEvent(createCharEvent(buf[i]));
917  }
918  return 0;
919 
920  case WM_MOUSEMOVE:
921  {
922  // Enable tracking.
923 
924  TRACKMOUSEEVENT track;
925  track.cbSize = sizeof(TRACKMOUSEEVENT);
926  track.dwFlags = TME_LEAVE;
927  track.hwndTrack = m_hwnd;
928  track.dwHoverTime = HOVER_DEFAULT;
929  TrackMouseEvent(&track);
930 
931  // Post event.
932 
933  postEvent(createMouseEvent(true, Vec2i((short)LOWORD(lParam), (short)HIWORD(lParam))));
934  }
935  return 0;
936 
937  case WM_MOUSELEAVE:
938  if (!m_mouseDragCount)
939  postEvent(createMouseEvent(false, 0));
940  return 0;
941 
942  case WM_LBUTTONDOWN:
943  case WM_LBUTTONUP:
944  case WM_RBUTTONDOWN:
945  case WM_RBUTTONUP:
946  case WM_MBUTTONDOWN:
947  case WM_MBUTTONUP:
948  {
949  // Identify the key.
950 
951  String key;
952  bool down;
953  switch (uMsg)
954  {
955  case WM_LBUTTONDOWN: key = FW_KEY_MOUSE_LEFT; down = true; break;
956  case WM_LBUTTONUP: key = FW_KEY_MOUSE_LEFT; down = false; break;
957  case WM_RBUTTONDOWN: key = FW_KEY_MOUSE_RIGHT; down = true; break;
958  case WM_RBUTTONUP: key = FW_KEY_MOUSE_RIGHT; down = false; break;
959  case WM_MBUTTONDOWN: key = FW_KEY_MOUSE_MIDDLE; down = true; break;
960  case WM_MBUTTONUP: key = FW_KEY_MOUSE_MIDDLE; down = false; break;
961  default: FW_ASSERT(false); return 0;
962  }
963 
964  // Update drag status.
965 
966  if (down && !m_keysDown.contains(key))
967  {
968  m_keysDown.add(key);
969  if (!m_mouseDragCount)
970  SetCapture(m_hwnd);
971  m_mouseDragCount++;
972  }
973  else if (!down && m_keysDown.contains(key))
974  {
975  m_keysDown.remove(key);
976  m_mouseDragCount--;
977  if (!m_mouseDragCount)
978  ReleaseCapture();
979  }
980 
981  // Post event.
982 
983  postEvent(createKeyEvent(down, key));
984  }
985  return 0;
986 
987  case WM_MOUSEWHEEL:
988  m_mouseWheelAcc += (short)HIWORD(wParam);
989  while (m_mouseWheelAcc >= 120)
990  {
991  postEvent(createKeyEvent(true, FW_KEY_WHEEL_UP));
992  postEvent(createKeyEvent(false, FW_KEY_WHEEL_UP));
993  m_mouseWheelAcc -= 120;
994  }
995  while (m_mouseWheelAcc <= -120)
996  {
997  postEvent(createKeyEvent(true, FW_KEY_WHEEL_DOWN));
998  postEvent(createKeyEvent(false, FW_KEY_WHEEL_DOWN));
999  m_mouseWheelAcc += 120;
1000  }
1001  return 0;
1002 
1003  case WM_DROPFILES:
1004  postEvent(createFileEvent(EventType_DropFiles, (HDROP)wParam));
1005  return 0;
1006 
1007  default:
1008  break;
1009  }
1010 
1011  return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
1012 }
1013 
1014 //------------------------------------------------------------------------
static UPTR setWindowLong(HWND hwnd, int idx, UPTR value)
Definition: Window.cpp:573
#define NULL
Definition: Defs.hpp:39
String showFileDialog(const String &title, bool save, const String &filters="", const String &initialDir="", bool forceInitialDir=false)
Definition: Window.cpp:321
#define FW_KEY_MOUSE_RIGHT
Definition: Keys.hpp:39
void enableDrop(bool enable)
Definition: Window.cpp:268
String substring(int start, int end) const
Definition: String.cpp:96
bool endsWith(const String &str) const
Definition: String.cpp:273
const char * getPtr(void) const
Definition: String.hpp:51
__w64 U32 UPTR
Definition: Defs.hpp:106
int indexOf(char chr) const
Definition: String.hpp:78
void swapBuffers(void)
Definition: GLContext.cpp:276
static void staticDeinit(void)
Definition: Window.cpp:535
void addListener(Listener *listener)
Definition: Window.cpp:282
unsigned __int64 U64
Definition: Defs.hpp:97
void failWin32Error(const char *funcName)
Definition: Defs.cpp:345
bool getDiscardEvents(void)
Definition: Defs.cpp:387
String vkeyToKey(U32 vkey)
Definition: Keys.cpp:72
Vec2i getSize(void) const
Definition: Window.cpp:129
const Config & getConfig(void) const
Definition: GLContext.hpp:141
String toLower(void) const
Definition: String.cpp:245
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level GLsizei GLuint framebuffers GLuint const GLchar name GLenum GLintptr GLsizeiptr GLvoid data GLuint GLenum GLint param GLuint GLenum GLint param GLhandleARB programObj GLenum GLenum GLsizei GLsizei height GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid pixels GLint GLsizei const GLfloat value GLint GLfloat GLfloat v1 GLint GLfloat GLfloat GLfloat v2 GLint GLsizei const GLfloat value GLint GLsizei GLboolean const GLfloat value GLuint program GLuint GLfloat x
Definition: DLLImports.inl:363
#define FW_KEY_WHEEL_DOWN
Definition: Keys.hpp:42
void repaint(void)
Definition: Window.cpp:216
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type GLsizei const GLuint framebuffers GLsizei const GLuint renderbuffers GLuint v GLuint v GLenum GLenum GLenum GLuint GLint level GLsizei GLuint framebuffers GLuint const GLchar name GLenum GLintptr GLsizeiptr GLvoid data GLuint GLenum GLint param GLuint GLenum GLint param GLhandleARB programObj GLenum GLenum GLsizei GLsizei height GLenum GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid pixels GLint GLsizei const GLfloat value GLint GLfloat GLfloat v1 GLint GLfloat GLfloat GLfloat v2 GLint GLsizei const GLfloat value GLint GLsizei GLboolean const GLfloat value GLuint program GLuint GLfloat GLfloat y
Definition: DLLImports.inl:363
void removeListener(Listener *listener)
Definition: Window.cpp:293
virtual bool handleEvent(const Event &ev)=0
void showModalMessage(const String &msg)
Definition: Window.cpp:487
bool setDiscardEvents(bool discard)
Definition: Defs.cpp:378
void setVisible(bool visible)
Definition: Window.cpp:138
#define FW_KEY_MOUSE_MIDDLE
Definition: Keys.hpp:40
void realize(void)
Definition: Window.cpp:184
#define FW_ASSERT(X)
Definition: Defs.hpp:67
bool isMouseDragging(void) const
Definition: Window.hpp:130
signed int S32
Definition: Defs.hpp:88
S32 keyToUnicode(const String &key)
Definition: Keys.cpp:44
int getLength(void) const
Definition: String.hpp:49
void setSize(const Vec2i &size)
Definition: Window.cpp:106
int incNestingLevel(int delta)
Definition: Defs.cpp:369
String sprintf(const char *fmt,...)
Definition: Defs.cpp:241
CUdevice int ordinal char int len
Definition: DLLImports.inl:48
GLContext * getGL(void)
Definition: Window.cpp:203
unsigned int U32
Definition: Defs.hpp:85
void removeListeners(void)
Definition: Window.cpp:304
bool hasError(void)
Definition: Defs.cpp:289
static void traverseDirectory(const char *root, Array< String > &names)
Definition: Window.cpp:609
void showMessageDialog(const String &title, const String &text)
Definition: Window.cpp:312
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value
Definition: DLLImports.inl:84
static void pollMessages(void)
Definition: Window.cpp:593
void setView(const Vec2i &pos, const Vec2i &size)
Definition: GLContext.cpp:287
void setGLConfig(const GLContext::Config &config)
Definition: Window.cpp:195
~Window(void)
Definition: Window.cpp:85
String & appendf(const char *fmt,...)
Definition: String.cpp:207
#define FW_ARRAY_SIZE(X)
Definition: Defs.hpp:79
unsigned char U8
Definition: Defs.hpp:83
static HWND createHWND(void)
Definition: Window.cpp:550
static void staticInit(void)
Definition: Window.cpp:502
Window(void)
Definition: Window.cpp:54
#define FW_KEY_MOUSE_LEFT
Definition: Keys.hpp:38
void failIfError(void)
Definition: Defs.cpp:361
Array< String > showDirLoadDialog(const String &title, const String &initialDir="")
Definition: Window.cpp:455
#define FW_KEY_WHEEL_UP
Definition: Keys.hpp:41
EventType type
Definition: Window.hpp:69
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void * p
Definition: DLLImports.inl:66
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr const GLvoid GLenum usage GLuint shader GLenum type
Definition: DLLImports.inl:323
void setTitle(const String &title)
Definition: Window.cpp:95
void setFullScreen(bool isFull)
Definition: Window.cpp:147
static void yield(void)
Definition: Thread.cpp:338
CUdevice int ordinal char int CUdevice dev CUdevprop CUdevice dev CUcontext ctx CUcontext ctx CUcontext pctx CUmodule const void image CUmodule const void fatCubin CUfunction CUmodule const char name void p CUfunction unsigned int bytes CUtexref pTexRef CUtexref CUarray unsigned int Flags CUtexref int CUaddress_mode am CUtexref unsigned int Flags CUaddress_mode CUtexref int dim CUarray_format int CUtexref hTexRef CUfunction unsigned int numbytes CUfunction int float value CUfunction int CUtexref hTexRef CUfunction int int grid_height CUevent unsigned int Flags CUevent hEvent CUevent hEvent CUstream unsigned int Flags CUstream hStream GLuint bufferobj unsigned int CUdevice dev CUdeviceptr unsigned int CUmodule const char name CUdeviceptr unsigned int bytesize CUdeviceptr dptr void unsigned int bytesize void CUdeviceptr unsigned int ByteCount CUarray unsigned int CUdeviceptr unsigned int ByteCount CUarray unsigned int const void unsigned int ByteCount CUarray unsigned int CUarray unsigned int unsigned int ByteCount void CUarray unsigned int unsigned int CUstream hStream const CUDA_MEMCPY2D pCopy CUdeviceptr const void unsigned int CUstream hStream const CUDA_MEMCPY2D CUstream hStream CUdeviceptr unsigned char unsigned int N CUdeviceptr unsigned int unsigned int N CUdeviceptr unsigned int unsigned short unsigned int unsigned int Height CUarray const CUDA_ARRAY_DESCRIPTOR pAllocateArray CUarray const CUDA_ARRAY3D_DESCRIPTOR pAllocateArray unsigned int CUtexref CUdeviceptr unsigned int bytes CUcontext unsigned int CUdevice device GLenum texture GLenum GLuint buffer GLenum GLuint renderbuffer GLenum GLsizeiptr size
Definition: DLLImports.inl:319
void enablePaste(bool enable)
Definition: Window.cpp:275
S32 getSize(void) const
void requestClose(void)
Definition: Window.cpp:261
static void realizeAll(void)
Definition: Window.cpp:584
void repaintNow(void)
Definition: Window.cpp:223
void drawModalMessage(const String &msg)
Definition: GLContext.cpp:786
void makeCurrent(void)
Definition: GLContext.cpp:260