/indra/llwindow/llwindowwin32.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 2253 lines · 1670 code · 321 blank · 262 comment · 237 complexity · 671c1e52977dd8d0791b4e195087f1b2 MD5 · raw file

Large files are truncated click here to view the full file

  1. /**
  2. * @file llwindowwin32.cpp
  3. * @brief Platform-dependent implementation of llwindow
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "linden_common.h"
  27. #if LL_WINDOWS && !LL_MESA_HEADLESS
  28. #include "llwindowwin32.h"
  29. // LLWindow library includes
  30. #include "llkeyboardwin32.h"
  31. #include "lldragdropwin32.h"
  32. #include "llpreeditor.h"
  33. #include "llwindowcallbacks.h"
  34. // Linden library includes
  35. #include "llerror.h"
  36. #include "llgl.h"
  37. #include "llstring.h"
  38. #include "lldir.h"
  39. #include "llglslshader.h"
  40. // System includes
  41. #include <commdlg.h>
  42. #include <WinUser.h>
  43. #include <mapi.h>
  44. #include <process.h> // for _spawn
  45. #include <shellapi.h>
  46. #include <fstream>
  47. #include <Imm.h>
  48. // Require DirectInput version 8
  49. #define DIRECTINPUT_VERSION 0x0800
  50. #include <dinput.h>
  51. #include <Dbt.h.>
  52. #include "llmemtype.h"
  53. // culled from winuser.h
  54. #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */
  55. const S32 WM_MOUSEWHEEL = 0x020A;
  56. #endif
  57. #ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */
  58. const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */
  59. #endif
  60. const S32 MAX_MESSAGE_PER_UPDATE = 20;
  61. const S32 BITS_PER_PIXEL = 32;
  62. const S32 MAX_NUM_RESOLUTIONS = 32;
  63. const F32 ICON_FLASH_TIME = 0.5f;
  64. extern BOOL gDebugWindowProc;
  65. LPWSTR gIconResource = IDI_APPLICATION;
  66. LLW32MsgCallback gAsyncMsgCallback = NULL;
  67. //
  68. // LLWindowWin32
  69. //
  70. void show_window_creation_error(const std::string& title)
  71. {
  72. LL_WARNS("Window") << title << LL_ENDL;
  73. }
  74. //static
  75. BOOL LLWindowWin32::sIsClassRegistered = FALSE;
  76. BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE;
  77. BOOL LLWindowWin32::sWinIMEOpened = FALSE;
  78. HKL LLWindowWin32::sWinInputLocale = 0;
  79. DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE;
  80. DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
  81. LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
  82. // The following class LLWinImm delegates Windows IMM APIs.
  83. // We need this because some language versions of Windows,
  84. // e.g., US version of Windows XP, doesn't install IMM32.DLL
  85. // as a default, and we can't link against imm32.lib statically.
  86. // I believe DLL loading of this type is best suited to do
  87. // in a static initialization of a class. What I'm not sure is
  88. // whether it follows the Linden Conding Standard...
  89. // See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
  90. class LLWinImm
  91. {
  92. public:
  93. static bool isAvailable() { return sTheInstance.mHImmDll != NULL; }
  94. public:
  95. // Wrappers for IMM API.
  96. static BOOL isIME(HKL hkl);
  97. static HWND getDefaultIMEWnd(HWND hwnd);
  98. static HIMC getContext(HWND hwnd);
  99. static BOOL releaseContext(HWND hwnd, HIMC himc);
  100. static BOOL getOpenStatus(HIMC himc);
  101. static BOOL setOpenStatus(HIMC himc, BOOL status);
  102. static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence);
  103. static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);
  104. static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);
  105. static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);
  106. static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length);
  107. static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength);
  108. static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont);
  109. static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
  110. static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
  111. private:
  112. LLWinImm();
  113. ~LLWinImm();
  114. private:
  115. // Pointers to IMM API.
  116. BOOL (WINAPI *mImmIsIME)(HKL);
  117. HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND);
  118. HIMC (WINAPI *mImmGetContext)(HWND);
  119. BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC);
  120. BOOL (WINAPI *mImmGetOpenStatus)(HIMC);
  121. BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
  122. BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
  123. BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
  124. BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
  125. BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
  126. LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
  127. BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
  128. BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
  129. BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
  130. BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
  131. private:
  132. HMODULE mHImmDll;
  133. static LLWinImm sTheInstance;
  134. };
  135. LLWinImm LLWinImm::sTheInstance;
  136. LLWinImm::LLWinImm() : mHImmDll(NULL)
  137. {
  138. // Check system metrics
  139. if ( !GetSystemMetrics( SM_DBCSENABLED ) )
  140. return;
  141. mHImmDll = LoadLibraryA("Imm32");
  142. if (mHImmDll != NULL)
  143. {
  144. mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME");
  145. mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
  146. mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext");
  147. mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext");
  148. mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus");
  149. mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus");
  150. mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
  151. mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus");
  152. mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
  153. mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
  154. mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
  155. mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
  156. mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
  157. mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
  158. mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME");
  159. if (mImmIsIME == NULL ||
  160. mImmGetDefaultIMEWnd == NULL ||
  161. mImmGetContext == NULL ||
  162. mImmReleaseContext == NULL ||
  163. mImmGetOpenStatus == NULL ||
  164. mImmSetOpenStatus == NULL ||
  165. mImmGetConversionStatus == NULL ||
  166. mImmSetConversionStatus == NULL ||
  167. mImmGetCompostitionWindow == NULL ||
  168. mImmSetCompostitionWindow == NULL ||
  169. mImmGetCompositionString == NULL ||
  170. mImmSetCompositionString == NULL ||
  171. mImmSetCompositionFont == NULL ||
  172. mImmSetCandidateWindow == NULL ||
  173. mImmNotifyIME == NULL)
  174. {
  175. // If any of the above API entires are not found, we can't use IMM API.
  176. // So, turn off the IMM support. We should log some warning message in
  177. // the case, since it is very unusual; these APIs are available from
  178. // the beginning, and all versions of IMM32.DLL should have them all.
  179. // Unfortunately, this code may be executed before initialization of
  180. // the logging channel (llwarns), and we can't do it here... Yes, this
  181. // is one of disadvantages to use static constraction to DLL loading.
  182. FreeLibrary(mHImmDll);
  183. mHImmDll = NULL;
  184. // If we unload the library, make sure all the function pointers are cleared
  185. mImmIsIME = NULL;
  186. mImmGetDefaultIMEWnd = NULL;
  187. mImmGetContext = NULL;
  188. mImmReleaseContext = NULL;
  189. mImmGetOpenStatus = NULL;
  190. mImmSetOpenStatus = NULL;
  191. mImmGetConversionStatus = NULL;
  192. mImmSetConversionStatus = NULL;
  193. mImmGetCompostitionWindow = NULL;
  194. mImmSetCompostitionWindow = NULL;
  195. mImmGetCompositionString = NULL;
  196. mImmSetCompositionString = NULL;
  197. mImmSetCompositionFont = NULL;
  198. mImmSetCandidateWindow = NULL;
  199. mImmNotifyIME = NULL;
  200. }
  201. }
  202. }
  203. // static
  204. BOOL LLWinImm::isIME(HKL hkl)
  205. {
  206. if ( sTheInstance.mImmIsIME )
  207. return sTheInstance.mImmIsIME(hkl);
  208. return FALSE;
  209. }
  210. // static
  211. HIMC LLWinImm::getContext(HWND hwnd)
  212. {
  213. if ( sTheInstance.mImmGetContext )
  214. return sTheInstance.mImmGetContext(hwnd);
  215. return 0;
  216. }
  217. //static
  218. BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc)
  219. {
  220. if ( sTheInstance.mImmIsIME )
  221. return sTheInstance.mImmReleaseContext(hwnd, himc);
  222. return FALSE;
  223. }
  224. // static
  225. BOOL LLWinImm::getOpenStatus(HIMC himc)
  226. {
  227. if ( sTheInstance.mImmGetOpenStatus )
  228. return sTheInstance.mImmGetOpenStatus(himc);
  229. return FALSE;
  230. }
  231. // static
  232. BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status)
  233. {
  234. if ( sTheInstance.mImmSetOpenStatus )
  235. return sTheInstance.mImmSetOpenStatus(himc, status);
  236. return FALSE;
  237. }
  238. // static
  239. BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)
  240. {
  241. if ( sTheInstance.mImmGetConversionStatus )
  242. return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence);
  243. return FALSE;
  244. }
  245. // static
  246. BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)
  247. {
  248. if ( sTheInstance.mImmSetConversionStatus )
  249. return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence);
  250. return FALSE;
  251. }
  252. // static
  253. BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)
  254. {
  255. if ( sTheInstance.mImmGetCompostitionWindow )
  256. return sTheInstance.mImmGetCompostitionWindow(himc, form);
  257. return FALSE;
  258. }
  259. // static
  260. BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)
  261. {
  262. if ( sTheInstance.mImmSetCompostitionWindow )
  263. return sTheInstance.mImmSetCompostitionWindow(himc, form);
  264. return FALSE;
  265. }
  266. // static
  267. LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)
  268. {
  269. if ( sTheInstance.mImmGetCompositionString )
  270. return sTheInstance.mImmGetCompositionString(himc, index, data, length);
  271. return FALSE;
  272. }
  273. // static
  274. BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)
  275. {
  276. if ( sTheInstance.mImmSetCompositionString )
  277. return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
  278. return FALSE;
  279. }
  280. // static
  281. BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)
  282. {
  283. if ( sTheInstance.mImmSetCompositionFont )
  284. return sTheInstance.mImmSetCompositionFont(himc, pFont);
  285. return FALSE;
  286. }
  287. // static
  288. BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)
  289. {
  290. if ( sTheInstance.mImmSetCandidateWindow )
  291. return sTheInstance.mImmSetCandidateWindow(himc, form);
  292. return FALSE;
  293. }
  294. // static
  295. BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)
  296. {
  297. if ( sTheInstance.mImmNotifyIME )
  298. return sTheInstance.mImmNotifyIME(himc, action, index, value);
  299. return FALSE;
  300. }
  301. // ----------------------------------------------------------------------------------------
  302. LLWinImm::~LLWinImm()
  303. {
  304. if (mHImmDll != NULL)
  305. {
  306. FreeLibrary(mHImmDll);
  307. mHImmDll = NULL;
  308. }
  309. }
  310. LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
  311. const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
  312. S32 height, U32 flags,
  313. BOOL fullscreen, BOOL clearBg,
  314. BOOL disable_vsync, BOOL use_gl,
  315. BOOL ignore_pixel_depth,
  316. U32 fsaa_samples)
  317. : LLWindow(callbacks, fullscreen, flags)
  318. {
  319. mFSAASamples = fsaa_samples;
  320. mIconResource = gIconResource;
  321. mOverrideAspectRatio = 0.f;
  322. mNativeAspectRatio = 0.f;
  323. mMousePositionModified = FALSE;
  324. mInputProcessingPaused = FALSE;
  325. mPreeditor = NULL;
  326. mKeyCharCode = 0;
  327. mKeyScanCode = 0;
  328. mKeyVirtualKey = 0;
  329. mhDC = NULL;
  330. mhRC = NULL;
  331. // Initialize the keyboard
  332. gKeyboard = new LLKeyboardWin32();
  333. gKeyboard->setCallbacks(callbacks);
  334. // Initialize the Drag and Drop functionality
  335. mDragDrop = new LLDragDropWin32;
  336. // Initialize (boot strap) the Language text input management,
  337. // based on the system's (user's) default settings.
  338. allowLanguageTextInput(mPreeditor, FALSE);
  339. WNDCLASS wc;
  340. RECT window_rect;
  341. // Set the window title
  342. if (title.empty())
  343. {
  344. mWindowTitle = new WCHAR[50];
  345. wsprintf(mWindowTitle, L"OpenGL Window");
  346. }
  347. else
  348. {
  349. mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars.
  350. mbstowcs(mWindowTitle, title.c_str(), 255);
  351. mWindowTitle[255] = 0;
  352. }
  353. // Set the window class name
  354. if (name.empty())
  355. {
  356. mWindowClassName = new WCHAR[50];
  357. wsprintf(mWindowClassName, L"OpenGL Window");
  358. }
  359. else
  360. {
  361. mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars.
  362. mbstowcs(mWindowClassName, name.c_str(), 255);
  363. mWindowClassName[255] = 0;
  364. }
  365. // We're not clipping yet
  366. SetRect( &mOldMouseClip, 0, 0, 0, 0 );
  367. // Make an instance of our window then define the window class
  368. mhInstance = GetModuleHandle(NULL);
  369. mWndProc = NULL;
  370. mSwapMethod = SWAP_METHOD_UNDEFINED;
  371. // No WPARAM yet.
  372. mLastSizeWParam = 0;
  373. // Windows GDI rects don't include rightmost pixel
  374. window_rect.left = (long) 0;
  375. window_rect.right = (long) width;
  376. window_rect.top = (long) 0;
  377. window_rect.bottom = (long) height;
  378. // Grab screen size to sanitize the window
  379. S32 window_border_y = GetSystemMetrics(SM_CYBORDER);
  380. S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN);
  381. S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN);
  382. S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  383. S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  384. if (x < virtual_screen_x) x = virtual_screen_x;
  385. if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y;
  386. if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width;
  387. if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height;
  388. if (!sIsClassRegistered)
  389. {
  390. // Force redraw when resized and create a private device context
  391. // Makes double click messages.
  392. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
  393. // Set message handler function
  394. wc.lpfnWndProc = (WNDPROC) mainWindowProc;
  395. // unused
  396. wc.cbClsExtra = 0;
  397. wc.cbWndExtra = 0;
  398. wc.hInstance = mhInstance;
  399. wc.hIcon = LoadIcon(mhInstance, mIconResource);
  400. // We will set the cursor ourselves
  401. wc.hCursor = NULL;
  402. // background color is not used
  403. if (clearBg)
  404. {
  405. wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  406. }
  407. else
  408. {
  409. wc.hbrBackground = (HBRUSH) NULL;
  410. }
  411. // we don't use windows menus
  412. wc.lpszMenuName = NULL;
  413. wc.lpszClassName = mWindowClassName;
  414. if (!RegisterClass(&wc))
  415. {
  416. OSMessageBox(mCallbacks->translateString("MBRegClassFailed"),
  417. mCallbacks->translateString("MBError"), OSMB_OK);
  418. return;
  419. }
  420. sIsClassRegistered = TRUE;
  421. }
  422. //-----------------------------------------------------------------------
  423. // Get the current refresh rate
  424. //-----------------------------------------------------------------------
  425. DEVMODE dev_mode;
  426. ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
  427. dev_mode.dmSize = sizeof(DEVMODE);
  428. DWORD current_refresh;
  429. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  430. {
  431. current_refresh = dev_mode.dmDisplayFrequency;
  432. mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight);
  433. }
  434. else
  435. {
  436. current_refresh = 60;
  437. }
  438. //-----------------------------------------------------------------------
  439. // Drop resolution and go fullscreen
  440. // use a display mode with our desired size and depth, with a refresh
  441. // rate as close at possible to the users' default
  442. //-----------------------------------------------------------------------
  443. if (mFullscreen)
  444. {
  445. BOOL success = FALSE;
  446. DWORD closest_refresh = 0;
  447. for (S32 mode_num = 0;; mode_num++)
  448. {
  449. if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
  450. {
  451. break;
  452. }
  453. if (dev_mode.dmPelsWidth == width &&
  454. dev_mode.dmPelsHeight == height &&
  455. dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
  456. {
  457. success = TRUE;
  458. if ((dev_mode.dmDisplayFrequency - current_refresh)
  459. < (closest_refresh - current_refresh))
  460. {
  461. closest_refresh = dev_mode.dmDisplayFrequency;
  462. }
  463. }
  464. }
  465. if (closest_refresh == 0)
  466. {
  467. LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
  468. //success = FALSE;
  469. if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  470. {
  471. success = FALSE;
  472. }
  473. else
  474. {
  475. if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
  476. {
  477. LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL;
  478. window_rect.right=width=dev_mode.dmPelsWidth;
  479. window_rect.bottom=height=dev_mode.dmPelsHeight;
  480. success = TRUE;
  481. }
  482. else
  483. {
  484. LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL;
  485. success = FALSE;
  486. }
  487. }
  488. }
  489. // If we found a good resolution, use it.
  490. if (success)
  491. {
  492. success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
  493. }
  494. // Keep a copy of the actual current device mode in case we minimize
  495. // and change the screen resolution. JC
  496. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
  497. // If it failed, we don't want to run fullscreen
  498. if (success)
  499. {
  500. mFullscreen = TRUE;
  501. mFullscreenWidth = dev_mode.dmPelsWidth;
  502. mFullscreenHeight = dev_mode.dmPelsHeight;
  503. mFullscreenBits = dev_mode.dmBitsPerPel;
  504. mFullscreenRefresh = dev_mode.dmDisplayFrequency;
  505. LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
  506. << "x" << dev_mode.dmPelsHeight
  507. << "x" << dev_mode.dmBitsPerPel
  508. << " @ " << dev_mode.dmDisplayFrequency
  509. << LL_ENDL;
  510. }
  511. else
  512. {
  513. mFullscreen = FALSE;
  514. mFullscreenWidth = -1;
  515. mFullscreenHeight = -1;
  516. mFullscreenBits = -1;
  517. mFullscreenRefresh = -1;
  518. std::map<std::string,std::string> args;
  519. args["[WIDTH]"] = llformat("%d", width);
  520. args["[HEIGHT]"] = llformat ("%d", height);
  521. OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args),
  522. mCallbacks->translateString("MBError"), OSMB_OK);
  523. }
  524. }
  525. // TODO: add this after resolving _WIN32_WINNT issue
  526. // if (!fullscreen)
  527. // {
  528. // TRACKMOUSEEVENT track_mouse_event;
  529. // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
  530. // track_mouse_event.dwFlags = TME_LEAVE;
  531. // track_mouse_event.hwndTrack = mWindowHandle;
  532. // track_mouse_event.dwHoverTime = HOVER_DEFAULT;
  533. // TrackMouseEvent( &track_mouse_event );
  534. // }
  535. //-----------------------------------------------------------------------
  536. // Create GL drawing context
  537. //-----------------------------------------------------------------------
  538. LLCoordScreen windowPos(x,y);
  539. LLCoordScreen windowSize(window_rect.right - window_rect.left,
  540. window_rect.bottom - window_rect.top);
  541. if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos))
  542. {
  543. return;
  544. }
  545. //start with arrow cursor
  546. initCursors();
  547. setCursor( UI_CURSOR_ARROW );
  548. // Initialize (boot strap) the Language text input management,
  549. // based on the system's (or user's) default settings.
  550. allowLanguageTextInput(NULL, FALSE);
  551. }
  552. LLWindowWin32::~LLWindowWin32()
  553. {
  554. delete mDragDrop;
  555. delete [] mWindowTitle;
  556. mWindowTitle = NULL;
  557. delete [] mSupportedResolutions;
  558. mSupportedResolutions = NULL;
  559. delete mWindowClassName;
  560. mWindowClassName = NULL;
  561. }
  562. void LLWindowWin32::show()
  563. {
  564. ShowWindow(mWindowHandle, SW_SHOW);
  565. SetForegroundWindow(mWindowHandle);
  566. SetFocus(mWindowHandle);
  567. }
  568. void LLWindowWin32::hide()
  569. {
  570. setMouseClipping(FALSE);
  571. ShowWindow(mWindowHandle, SW_HIDE);
  572. }
  573. //virtual
  574. void LLWindowWin32::minimize()
  575. {
  576. setMouseClipping(FALSE);
  577. showCursor();
  578. ShowWindow(mWindowHandle, SW_MINIMIZE);
  579. }
  580. //virtual
  581. void LLWindowWin32::restore()
  582. {
  583. ShowWindow(mWindowHandle, SW_RESTORE);
  584. SetForegroundWindow(mWindowHandle);
  585. SetFocus(mWindowHandle);
  586. }
  587. // close() destroys all OS-specific code associated with a window.
  588. // Usually called from LLWindowManager::destroyWindow()
  589. void LLWindowWin32::close()
  590. {
  591. LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL;
  592. // Is window is already closed?
  593. if (!mWindowHandle)
  594. {
  595. return;
  596. }
  597. mDragDrop->reset();
  598. // Make sure cursor is visible and we haven't mangled the clipping state.
  599. setMouseClipping(FALSE);
  600. showCursor();
  601. // Go back to screen mode written in the registry.
  602. if (mFullscreen)
  603. {
  604. resetDisplayResolution();
  605. }
  606. // Clean up remaining GL state
  607. LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL;
  608. gGLManager.shutdownGL();
  609. LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL;
  610. if (mhRC)
  611. {
  612. if (!wglMakeCurrent(NULL, NULL))
  613. {
  614. LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
  615. }
  616. if (!wglDeleteContext(mhRC))
  617. {
  618. LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
  619. }
  620. mhRC = NULL;
  621. }
  622. // Restore gamma to the system values.
  623. restoreGamma();
  624. if (mhDC && !ReleaseDC(mWindowHandle, mhDC))
  625. {
  626. LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
  627. mhDC = NULL;
  628. }
  629. LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
  630. // Don't process events in our mainWindowProc any longer.
  631. SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
  632. // Make sure we don't leave a blank toolbar button.
  633. ShowWindow(mWindowHandle, SW_HIDE);
  634. // This causes WM_DESTROY to be sent *immediately*
  635. if (!DestroyWindow(mWindowHandle))
  636. {
  637. OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
  638. mCallbacks->translateString("MBShutdownErr"),
  639. OSMB_OK);
  640. }
  641. mWindowHandle = NULL;
  642. }
  643. BOOL LLWindowWin32::isValid()
  644. {
  645. return (mWindowHandle != NULL);
  646. }
  647. BOOL LLWindowWin32::getVisible()
  648. {
  649. return (mWindowHandle && IsWindowVisible(mWindowHandle));
  650. }
  651. BOOL LLWindowWin32::getMinimized()
  652. {
  653. return (mWindowHandle && IsIconic(mWindowHandle));
  654. }
  655. BOOL LLWindowWin32::getMaximized()
  656. {
  657. return (mWindowHandle && IsZoomed(mWindowHandle));
  658. }
  659. BOOL LLWindowWin32::maximize()
  660. {
  661. BOOL success = FALSE;
  662. if (!mWindowHandle) return success;
  663. WINDOWPLACEMENT placement;
  664. placement.length = sizeof(WINDOWPLACEMENT);
  665. success = GetWindowPlacement(mWindowHandle, &placement);
  666. if (!success) return success;
  667. placement.showCmd = SW_MAXIMIZE;
  668. success = SetWindowPlacement(mWindowHandle, &placement);
  669. return success;
  670. }
  671. BOOL LLWindowWin32::getFullscreen()
  672. {
  673. return mFullscreen;
  674. }
  675. BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
  676. {
  677. RECT window_rect;
  678. if (!mWindowHandle ||
  679. !GetWindowRect(mWindowHandle, &window_rect) ||
  680. NULL == position)
  681. {
  682. return FALSE;
  683. }
  684. position->mX = window_rect.left;
  685. position->mY = window_rect.top;
  686. return TRUE;
  687. }
  688. BOOL LLWindowWin32::getSize(LLCoordScreen *size)
  689. {
  690. RECT window_rect;
  691. if (!mWindowHandle ||
  692. !GetWindowRect(mWindowHandle, &window_rect) ||
  693. NULL == size)
  694. {
  695. return FALSE;
  696. }
  697. size->mX = window_rect.right - window_rect.left;
  698. size->mY = window_rect.bottom - window_rect.top;
  699. return TRUE;
  700. }
  701. BOOL LLWindowWin32::getSize(LLCoordWindow *size)
  702. {
  703. RECT client_rect;
  704. if (!mWindowHandle ||
  705. !GetClientRect(mWindowHandle, &client_rect) ||
  706. NULL == size)
  707. {
  708. return FALSE;
  709. }
  710. size->mX = client_rect.right - client_rect.left;
  711. size->mY = client_rect.bottom - client_rect.top;
  712. return TRUE;
  713. }
  714. BOOL LLWindowWin32::setPosition(const LLCoordScreen position)
  715. {
  716. LLCoordScreen size;
  717. if (!mWindowHandle)
  718. {
  719. return FALSE;
  720. }
  721. getSize(&size);
  722. moveWindow(position, size);
  723. return TRUE;
  724. }
  725. BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size)
  726. {
  727. LLCoordScreen position;
  728. getPosition(&position);
  729. if (!mWindowHandle)
  730. {
  731. return FALSE;
  732. }
  733. moveWindow(position, size);
  734. return TRUE;
  735. }
  736. // changing fullscreen resolution
  737. BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
  738. {
  739. GLuint pixel_format;
  740. DEVMODE dev_mode;
  741. ::ZeroMemory(&dev_mode, sizeof(DEVMODE));
  742. dev_mode.dmSize = sizeof(DEVMODE);
  743. DWORD current_refresh;
  744. DWORD dw_ex_style;
  745. DWORD dw_style;
  746. RECT window_rect;
  747. S32 width = size.mX;
  748. S32 height = size.mY;
  749. BOOL auto_show = FALSE;
  750. if (mhRC)
  751. {
  752. auto_show = TRUE;
  753. resetDisplayResolution();
  754. }
  755. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  756. {
  757. current_refresh = dev_mode.dmDisplayFrequency;
  758. }
  759. else
  760. {
  761. current_refresh = 60;
  762. }
  763. gGLManager.shutdownGL();
  764. //destroy gl context
  765. if (mhRC)
  766. {
  767. if (!wglMakeCurrent(NULL, NULL))
  768. {
  769. LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
  770. }
  771. if (!wglDeleteContext(mhRC))
  772. {
  773. LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
  774. }
  775. mhRC = NULL;
  776. }
  777. if (fullscreen)
  778. {
  779. mFullscreen = TRUE;
  780. BOOL success = FALSE;
  781. DWORD closest_refresh = 0;
  782. for (S32 mode_num = 0;; mode_num++)
  783. {
  784. if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
  785. {
  786. break;
  787. }
  788. if (dev_mode.dmPelsWidth == width &&
  789. dev_mode.dmPelsHeight == height &&
  790. dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
  791. {
  792. success = TRUE;
  793. if ((dev_mode.dmDisplayFrequency - current_refresh)
  794. < (closest_refresh - current_refresh))
  795. {
  796. closest_refresh = dev_mode.dmDisplayFrequency;
  797. }
  798. }
  799. }
  800. if (closest_refresh == 0)
  801. {
  802. LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
  803. return FALSE;
  804. }
  805. // If we found a good resolution, use it.
  806. if (success)
  807. {
  808. success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
  809. }
  810. // Keep a copy of the actual current device mode in case we minimize
  811. // and change the screen resolution. JC
  812. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
  813. if (success)
  814. {
  815. mFullscreen = TRUE;
  816. mFullscreenWidth = dev_mode.dmPelsWidth;
  817. mFullscreenHeight = dev_mode.dmPelsHeight;
  818. mFullscreenBits = dev_mode.dmBitsPerPel;
  819. mFullscreenRefresh = dev_mode.dmDisplayFrequency;
  820. LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
  821. << "x" << dev_mode.dmPelsHeight
  822. << "x" << dev_mode.dmBitsPerPel
  823. << " @ " << dev_mode.dmDisplayFrequency
  824. << LL_ENDL;
  825. window_rect.left = (long) 0;
  826. window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel
  827. window_rect.top = (long) 0;
  828. window_rect.bottom = (long) height;
  829. dw_ex_style = WS_EX_APPWINDOW;
  830. dw_style = WS_POPUP;
  831. // Move window borders out not to cover window contents
  832. AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
  833. }
  834. // If it failed, we don't want to run fullscreen
  835. else
  836. {
  837. mFullscreen = FALSE;
  838. mFullscreenWidth = -1;
  839. mFullscreenHeight = -1;
  840. mFullscreenBits = -1;
  841. mFullscreenRefresh = -1;
  842. LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
  843. return FALSE;
  844. }
  845. }
  846. else
  847. {
  848. mFullscreen = FALSE;
  849. window_rect.left = (long) (posp ? posp->mX : 0);
  850. window_rect.right = (long) width + window_rect.left; // Windows GDI rects don't include rightmost pixel
  851. window_rect.top = (long) (posp ? posp->mY : 0);
  852. window_rect.bottom = (long) height + window_rect.top;
  853. // Window with an edge
  854. dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  855. dw_style = WS_OVERLAPPEDWINDOW;
  856. }
  857. // don't post quit messages when destroying old windows
  858. mPostQuit = FALSE;
  859. // create window
  860. DestroyWindow(mWindowHandle);
  861. mWindowHandle = CreateWindowEx(dw_ex_style,
  862. mWindowClassName,
  863. mWindowTitle,
  864. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
  865. window_rect.left, // x pos
  866. window_rect.top, // y pos
  867. window_rect.right - window_rect.left, // width
  868. window_rect.bottom - window_rect.top, // height
  869. NULL,
  870. NULL,
  871. mhInstance,
  872. NULL);
  873. LL_INFOS("Window") << "window is created." << llendl ;
  874. //-----------------------------------------------------------------------
  875. // Create GL drawing context
  876. //-----------------------------------------------------------------------
  877. static PIXELFORMATDESCRIPTOR pfd =
  878. {
  879. sizeof(PIXELFORMATDESCRIPTOR),
  880. 1,
  881. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  882. PFD_TYPE_RGBA,
  883. BITS_PER_PIXEL,
  884. 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused
  885. 8, // alpha bits
  886. 0, // alpha shift
  887. 0, // accum bits
  888. 0, 0, 0, 0, // accum RGBA
  889. 24, // depth bits
  890. 8, // stencil bits, avi added for stencil test
  891. 0,
  892. PFD_MAIN_PLANE,
  893. 0,
  894. 0, 0, 0
  895. };
  896. if (!(mhDC = GetDC(mWindowHandle)))
  897. {
  898. close();
  899. OSMessageBox(mCallbacks->translateString("MBDevContextErr"),
  900. mCallbacks->translateString("MBError"), OSMB_OK);
  901. return FALSE;
  902. }
  903. if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
  904. {
  905. close();
  906. OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
  907. mCallbacks->translateString("MBError"), OSMB_OK);
  908. return FALSE;
  909. }
  910. // Verify what pixel format we actually received.
  911. if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
  912. &pfd))
  913. {
  914. close();
  915. OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"),
  916. mCallbacks->translateString("MBError"), OSMB_OK);
  917. return FALSE;
  918. }
  919. // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash
  920. LL_INFOS("Window") << "--- begin pixel format dump ---" << llendl ;
  921. LL_INFOS("Window") << "pixel_format is " << pixel_format << llendl ;
  922. LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << llendl ;
  923. LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << llendl ;
  924. LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << llendl ;
  925. LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << llendl ;
  926. LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << llendl ;
  927. LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << llendl ;
  928. LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << llendl ;
  929. LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << llendl ;
  930. LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << llendl ;
  931. LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << llendl ;
  932. LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << llendl ;
  933. LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << llendl ;
  934. LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << llendl ;
  935. LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << llendl ;
  936. LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << llendl ;
  937. LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << llendl ;
  938. LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << llendl ;
  939. LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << llendl ;
  940. LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << llendl ;
  941. LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << llendl ;
  942. LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << llendl ;
  943. LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << llendl ;
  944. LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << llendl ;
  945. LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << llendl ;
  946. LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << llendl ;
  947. LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << llendl ;
  948. LL_INFOS("Window") << "--- end pixel format dump ---" << llendl ;
  949. if (pfd.cColorBits < 32)
  950. {
  951. close();
  952. OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"),
  953. mCallbacks->translateString("MBError"), OSMB_OK);
  954. return FALSE;
  955. }
  956. if (pfd.cAlphaBits < 8)
  957. {
  958. close();
  959. OSMessageBox(mCallbacks->translateString("MBAlpha"),
  960. mCallbacks->translateString("MBError"), OSMB_OK);
  961. return FALSE;
  962. }
  963. if (!SetPixelFormat(mhDC, pixel_format, &pfd))
  964. {
  965. close();
  966. OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
  967. mCallbacks->translateString("MBError"), OSMB_OK);
  968. return FALSE;
  969. }
  970. if (!(mhRC = wglCreateContext(mhDC)))
  971. {
  972. close();
  973. OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
  974. mCallbacks->translateString("MBError"), OSMB_OK);
  975. return FALSE;
  976. }
  977. if (!wglMakeCurrent(mhDC, mhRC))
  978. {
  979. close();
  980. OSMessageBox(mCallbacks->translateString("MBGLContextActErr"),
  981. mCallbacks->translateString("MBError"), OSMB_OK);
  982. return FALSE;
  983. }
  984. LL_INFOS("Window") << "Drawing context is created." << llendl ;
  985. gGLManager.initWGL();
  986. if (wglChoosePixelFormatARB)
  987. {
  988. // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we
  989. // can get exactly what we want.
  990. GLint attrib_list[256];
  991. S32 cur_attrib = 0;
  992. attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;
  993. attrib_list[cur_attrib++] = 24;
  994. attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB;
  995. attrib_list[cur_attrib++] = 8;
  996. attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;
  997. attrib_list[cur_attrib++] = GL_TRUE;
  998. attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB;
  999. attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB;
  1000. attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB;
  1001. attrib_list[cur_attrib++] = GL_TRUE;
  1002. attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB;
  1003. attrib_list[cur_attrib++] = GL_TRUE;
  1004. attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
  1005. attrib_list[cur_attrib++] = 24;
  1006. attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
  1007. attrib_list[cur_attrib++] = 8;
  1008. U32 end_attrib = 0;
  1009. if (mFSAASamples > 0)
  1010. {
  1011. end_attrib = cur_attrib;
  1012. attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB;
  1013. attrib_list[cur_attrib++] = GL_TRUE;
  1014. attrib_list[cur_attrib++] = WGL_SAMPLES_ARB;
  1015. attrib_list[cur_attrib++] = mFSAASamples;
  1016. }
  1017. // End the list
  1018. attrib_list[cur_attrib++] = 0;
  1019. GLint pixel_formats[256];
  1020. U32 num_formats = 0;
  1021. // First we try and get a 32 bit depth pixel format
  1022. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  1023. while(!result && mFSAASamples > 0)
  1024. {
  1025. llwarns << "FSAASamples: " << mFSAASamples << " not supported." << llendl ;
  1026. mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing
  1027. if(mFSAASamples < 2)
  1028. {
  1029. mFSAASamples = 0 ;
  1030. }
  1031. if (mFSAASamples > 0)
  1032. {
  1033. attrib_list[end_attrib + 3] = mFSAASamples;
  1034. }
  1035. else
  1036. {
  1037. cur_attrib = end_attrib ;
  1038. end_attrib = 0 ;
  1039. attrib_list[cur_attrib++] = 0 ; //end
  1040. }
  1041. result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  1042. if(result)
  1043. {
  1044. llwarns << "Only support FSAASamples: " << mFSAASamples << llendl ;
  1045. }
  1046. }
  1047. if (!result)
  1048. {
  1049. llwarns << "mFSAASamples: " << mFSAASamples << llendl ;
  1050. close();
  1051. show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit");
  1052. return FALSE;
  1053. }
  1054. if (!num_formats)
  1055. {
  1056. if (end_attrib > 0)
  1057. {
  1058. LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL;
  1059. attrib_list[end_attrib] = 0;
  1060. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  1061. if (!result)
  1062. {
  1063. close();
  1064. show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA");
  1065. return FALSE;
  1066. }
  1067. }
  1068. if (!num_formats)
  1069. {
  1070. LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL;
  1071. // Try 24-bit format
  1072. attrib_list[1] = 24;
  1073. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  1074. if (!result)
  1075. {
  1076. close();
  1077. show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit");
  1078. return FALSE;
  1079. }
  1080. if (!num_formats)
  1081. {
  1082. LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL;
  1083. attrib_list[1] = 16;
  1084. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  1085. if (!result || !num_formats)
  1086. {
  1087. close();
  1088. show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit");
  1089. return FALSE;
  1090. }
  1091. }
  1092. }
  1093. LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL;
  1094. }
  1095. LL_INFOS("Window") << "pixel formats done." << llendl ;
  1096. S32 swap_method = 0;
  1097. S32 cur_format = num_formats-1;
  1098. GLint swap_query = WGL_SWAP_METHOD_ARB;
  1099. BOOL found_format = FALSE;
  1100. while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
  1101. {
  1102. if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0)
  1103. {
  1104. found_format = TRUE;
  1105. }
  1106. else
  1107. {
  1108. --cur_format;
  1109. }
  1110. }
  1111. pixel_format = pixel_formats[cur_format];
  1112. if (mhDC != 0) // Does The Window Have A Device Context?
  1113. {
  1114. wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero
  1115. if (mhRC != 0) // Does The Window Have A Rendering Context?
  1116. {
  1117. wglDeleteContext (mhRC); // Release The Rendering Context
  1118. mhRC = 0; // Zero The Rendering Context
  1119. }
  1120. ReleaseDC (mWindowHandle, mhDC); // Release The Device Context
  1121. mhDC = 0; // Zero The Device Context
  1122. }
  1123. DestroyWindow (mWindowHandle); // Destroy The Window
  1124. mWindowHandle = CreateWindowEx(dw_ex_style,
  1125. mWindowClassName,
  1126. mWindowTitle,
  1127. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
  1128. window_rect.left, // x pos
  1129. window_rect.top, // y pos
  1130. window_rect.right - window_rect.left, // width
  1131. window_rect.bottom - window_rect.top, // height
  1132. NULL,
  1133. NULL,
  1134. mhInstance,
  1135. NULL);
  1136. LL_INFOS("Window") << "recreate window done." << llendl ;
  1137. if (!(mhDC = GetDC(mWindowHandle)))
  1138. {
  1139. close();
  1140. OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1141. return FALSE;
  1142. }
  1143. if (!SetPixelFormat(mhDC, pixel_format, &pfd))
  1144. {
  1145. close();
  1146. OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
  1147. mCallbacks->translateString("MBError"), OSMB_OK);
  1148. return FALSE;
  1149. }
  1150. if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
  1151. {
  1152. switch (swap_method)
  1153. {
  1154. case WGL_SWAP_EXCHANGE_ARB:
  1155. mSwapMethod = SWAP_METHOD_EXCHANGE;
  1156. LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL;
  1157. break;
  1158. case WGL_SWAP_COPY_ARB:
  1159. mSwapMethod = SWAP_METHOD_COPY;
  1160. LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL;
  1161. break;
  1162. case WGL_SWAP_UNDEFINED_ARB:
  1163. mSwapMethod = SWAP_METHOD_UNDEFINED;
  1164. LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL;
  1165. break;
  1166. default:
  1167. mSwapMethod = SWAP_METHOD_UNDEFINED;
  1168. LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL;
  1169. break;
  1170. }
  1171. }
  1172. }
  1173. else
  1174. {
  1175. LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL;
  1176. }
  1177. // Verify what pixel format we actually received.
  1178. if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
  1179. &pfd))
  1180. {
  1181. close();
  1182. OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1183. return FALSE;
  1184. }
  1185. LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits)
  1186. << " Alpha Bits " << S32(pfd.cAlphaBits)
  1187. << " Depth Bits " << S32(pfd.cDepthBits)
  1188. << LL_ENDL;
  1189. // make sure we have 32 bits per pixel
  1190. if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32)
  1191. {
  1192. close();
  1193. OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK);
  1194. return FALSE;
  1195. }
  1196. if (pfd.cAlphaBits < 8)
  1197. {
  1198. close();
  1199. OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK);
  1200. return FALSE;
  1201. }
  1202. mhRC = 0;
  1203. if (wglCreateContextAttribsARB)
  1204. { //attempt to create a specific versioned context
  1205. S32 attribs[] =
  1206. { //start at 4.2
  1207. WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
  1208. WGL_CONTEXT_MINOR_VERSION_ARB, 2,
  1209. WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
  1210. WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
  1211. 0
  1212. };
  1213. bool done = false;
  1214. while (!done)
  1215. {
  1216. mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs);
  1217. if (!mhRC)
  1218. {
  1219. if (attribs[3] > 0)
  1220. { //decrement minor version
  1221. attribs[3]--;
  1222. }
  1223. else if (attribs[1] > 3)
  1224. { //decrement major version and start minor version over at 3
  1225. attribs[1]--;
  1226. attribs[3] = 3;
  1227. }
  1228. else
  1229. { //we reached 3.0 and still failed, bail out
  1230. done = true;
  1231. }
  1232. }
  1233. else
  1234. {
  1235. llinfos << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << " context." << llendl;
  1236. done = true;
  1237. if (LLRender::sGLCoreProfile)
  1238. {
  1239. LLGLSLShader::sNoFixedFunction = true;
  1240. }
  1241. }
  1242. }
  1243. }
  1244. if (!mhRC && !(mhRC = wglCreateContext(mhDC)))
  1245. {
  1246. close();
  1247. OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1248. return FALSE;
  1249. }
  1250. if (!wglMakeCurrent(mhDC, mhRC))
  1251. {
  1252. close();
  1253. OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1254. return FALSE;
  1255. }
  1256. if (!gGLManager.initGL())
  1257. {
  1258. close();
  1259. OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1260. return FALSE;
  1261. }
  1262. // Disable vertical sync for swap
  1263. if (disable_vsync && wglSwapIntervalEXT)
  1264. {
  1265. LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
  1266. wglSwapIntervalEXT(0);
  1267. }
  1268. else
  1269. {
  1270. LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
  1271. }
  1272. SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
  1273. // register this window as handling drag/drop events from the OS
  1274. DragAcceptFiles( mWindowHandle, TRUE );
  1275. mDragDrop->init( mWindowHandle );
  1276. //register joystick timer callback
  1277. SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer
  1278. // ok to post quit messages now
  1279. mPostQuit = TRUE;
  1280. if (auto_show)
  1281. {
  1282. show();
  1283. glClearColor(0.0f, 0.0f, 0.0f, 0.f);
  1284. glClear(GL_COLOR_BUFFER_BIT);
  1285. swapBuffers();
  1286. }
  1287. return TRUE;
  1288. }
  1289. void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
  1290. {
  1291. if( mIsMouseClipping )
  1292. {
  1293. RECT client_rect_in_screen_space;
  1294. if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
  1295. {
  1296. ClipCursor( &client_rect_in_screen_space );
  1297. }
  1298. }
  1299. // if the window was already maximized, MoveWindow seems to still set the maximized flag even if
  1300. // the window is smaller than maximized.
  1301. // So we're going to do a restore first (which is a ShowWindow call) (SL-44655).
  1302. // THIS CAUSES DEV-15484 and DEV-15949
  1303. //ShowWindow(mWindowHandle, SW_RESTORE);
  1304. // NOW we can call MoveWindow
  1305. MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
  1306. }
  1307. BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
  1308. {
  1309. LLCoordScreen screen_pos;
  1310. mMousePositionModified = TRUE;
  1311. if (!mWindowHandle)
  1312. {
  1313. return FALSE;
  1314. }
  1315. if (!convertCoords(position, &screen_pos))
  1316. {
  1317. return FALSE;
  1318. }
  1319. // Inform the application of the new mouse position (needed for per-frame
  1320. // hover/picking to function).
  1321. LLCoordGL gl_pos;
  1322. convertCoords(position, &gl_pos);
  1323. mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
  1324. // DEV-18951 VWR-8524 Camera moves wildly when alt-clicking.
  1325. // Because we have preemptively notified the application of the new
  1326. // mouse position via handleMouseMove() above, we need to clear out
  1327. // any stale mouse move events. RN/JC
  1328. MSG msg;
  1329. while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
  1330. { }
  1331. return SetCursorPos(screen_pos.mX, screen_pos.mY);
  1332. }
  1333. BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
  1334. {
  1335. POINT cursor_point;
  1336. LLCoordScreen screen_pos;
  1337. if (!mWindowHandle ||
  1338. !GetCursorPos(&cursor_point))
  1339. {
  1340. return FALSE;
  1341. }
  1342. screen_pos.mX = cursor_point.x;
  1343. screen_pos.mY = cursor_point.y;
  1344. return convertCoords(screen_pos, position);
  1345. }
  1346. void LLWindowWin32::hideCursor()
  1347. {
  1348. while (ShowCursor(FALSE) >= 0)
  1349. {
  1350. // nothing, wait for cursor to push down
  1351. }
  1352. mCursorHidden = TRUE;
  1353. mHideCursorPermanent = TRUE;
  1354. }
  1355. void LLWindowWin32::showCursor()
  1356. {
  1357. // makes sure the cursor shows up
  1358. while (ShowCursor(TRUE) < 0)
  1359. {
  1360. // do nothing, wait for cursor to pop out
  1361. }
  1362. mCursorHidden = FALSE;
  1363. mHideCursorPermanent = FALSE;
  1364. }
  1365. void LLWindowWin32::showCursorFromMouseMove()
  1366. {
  1367. if (!mHideCursorPermanent)
  1368. {
  1369. showCursor();
  1370. }
  1371. }
  1372. void LLWindowWin32::hideCursorUntilMouseMove()
  1373. {
  1374. if (!mHideCursorPermanent)
  1375. {
  1376. hideCursor();
  1377. mHideCursorPermanent = FALSE;
  1378. }
  1379. }
  1380. BOOL LLWindowWin32::isCursorHidden()
  1381. {
  1382. return mCursorHidden;
  1383. }
  1384. HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name)
  1385. {
  1386. return (HCURSOR)LoadImage(mhInstance,
  1387. name,
  1388. IMAGE_CURSOR,
  1389. 0, // default width
  1390. 0, // default height
  1391. LR_DEFAULTCOLOR);
  1392. }
  1393. void LLWindowWin32::initCursors()
  1394. {
  1395. mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW);
  1396. mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT);
  1397. mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND);
  1398. mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM);
  1399. mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS);
  1400. mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE);
  1401. mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW);
  1402. mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE);
  1403. mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS);
  1404. mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO);
  1405. mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING);
  1406. HMODULE module = GetModuleHandle(NULL);
  1407. mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB"));
  1408. mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND"));
  1409. mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS"));
  1410. mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE"));
  1411. mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG"));
  1412. mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY"));
  1413. mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI"));
  1414. mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI"));
  1415. mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED"));
  1416. mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED"));
  1417. mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED"));
  1418. mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE"));
  1419. mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE"));
  1420. mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE"));
  1421. mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA"));
  1422. mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN"));
  1423. mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
  1424. mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
  1425. mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
  1426. mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT"));
  1427. mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY"));
  1428. mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN"));
  1429. // Color cursors
  1430. mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY"));
  1431. mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE"));
  1432. mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN"));
  1433. // Note: custom cursors that are not found make LoadCursor() return NULL.
  1434. for( S32 i = 0; i < UI_CURSOR_COUNT; i++ )
  1435. {
  1436. if( !mCursor[i] )
  1437. {
  1438. mCursor[i] = LoadCursor(NULL, IDC_ARROW);
  1439. }
  1440. }
  1441. }
  1442. void LLWindowWin32::updateCursor()
  1443. {
  1444. if (mNextCursor == UI_CURSOR_ARROW
  1445. && mBusyCount > 0)
  1446. {
  1447. mNextCursor = UI_CURSOR_WORKING;
  1448. }
  1449. if( mCurrentCursor != mNextCursor )
  1450. {
  1451. mCurrentCursor = mNextCursor;
  1452. SetCursor( mCursor[mNextCursor] );
  1453. }
  1454. }
  1455. ECursorType LLWindowWin32::getCursor() const
  1456. {
  1457. return mCurrentCursor;
  1458. }
  1459. void LLWindowWin32::captureMouse()
  1460. {
  1461. SetCapture(mWindowHandle);
  1462. }
  1463. void LLWindowWin32::releaseMouse()
  1464. {
  1465. // *NOTE:Mani ReleaseCapture will spawn new windows messages...
  1466. // which will in turn call our MainWindowProc. It therefore requires
  1467. // pausing *and more importantly resumption* of the mainlooptimeout...
  1468. // just like DispatchMessage below.
  1469. mCallbacks->handlePauseWatchdog(this);
  1470. ReleaseCapture();
  1471. mCallbacks->handleResumeWatchdog(this);
  1472. }
  1473. void LLWindowWin32::delayInputProcessing()
  1474. {
  1475. mInputProcessingPaused = TRUE;
  1476. }
  1477. void LLWindowWin32::gatherInput()
  1478. {
  1479. MSG msg;
  1480. int msg_count = 0;
  1481. LLMemType m1(LLMemType::MTYPE_GATHER_INPUT);
  1482. while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1483. {
  1484. mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
  1485. TranslateMessage(&msg);
  1486. // turn watchdog off in…