PageRenderTime 59ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llwindow/llwindowwin32.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 2253 lines | 1670 code | 321 blank | 262 comment | 234 complexity | 671c1e52977dd8d0791b4e195087f1b2 MD5 | raw file
Possible License(s): LGPL-2.1
  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 here to not fail if windows is doing something wacky
  1487. mCallbacks->handlePauseWatchdog(this);
  1488. DispatchMessage(&msg);
  1489. mCallbacks->handleResumeWatchdog(this);
  1490. msg_count++;
  1491. if ( mInputProcessingPaused )
  1492. {
  1493. break;
  1494. }
  1495. /* Attempted workaround for problem where typing fast and hitting
  1496. return would result in only part of the text being sent. JC
  1497. BOOL key_posted = TranslateMessage(&msg);
  1498. DispatchMessage(&msg);
  1499. msg_count++;
  1500. // If a key was translated, a WM_CHAR might have been posted to the end
  1501. // of the event queue. We need it immediately.
  1502. if (key_posted && msg.message == WM_KEYDOWN)
  1503. {
  1504. if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
  1505. {
  1506. TranslateMessage(&msg);
  1507. DispatchMessage(&msg);
  1508. msg_count++;
  1509. }
  1510. }
  1511. */
  1512. mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput");
  1513. // For async host by name support. Really hacky.
  1514. if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
  1515. {
  1516. gAsyncMsgCallback(msg);
  1517. }
  1518. }
  1519. mInputProcessingPaused = FALSE;
  1520. updateCursor();
  1521. // clear this once we've processed all mouse messages that might have occurred after
  1522. // we slammed the mouse position
  1523. mMousePositionModified = FALSE;
  1524. }
  1525. static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard");
  1526. static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse");
  1527. LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
  1528. {
  1529. LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
  1530. if (NULL != window_imp)
  1531. {
  1532. window_imp->mCallbacks->handleResumeWatchdog(window_imp);
  1533. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc");
  1534. // Has user provided their own window callback?
  1535. if (NULL != window_imp->mWndProc)
  1536. {
  1537. if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
  1538. {
  1539. // user has handled window message
  1540. return 0;
  1541. }
  1542. }
  1543. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc");
  1544. // Juggle to make sure we can get negative positions for when
  1545. // mouse is outside window.
  1546. LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
  1547. // This doesn't work, as LOWORD returns unsigned short.
  1548. //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
  1549. LLCoordGL gl_coord;
  1550. // pass along extended flag in mask
  1551. MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
  1552. BOOL eat_keystroke = TRUE;
  1553. switch(u_msg)
  1554. {
  1555. RECT update_rect;
  1556. S32 update_width;
  1557. S32 update_height;
  1558. case WM_TIMER:
  1559. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER");
  1560. window_imp->mCallbacks->handleTimerEvent(window_imp);
  1561. break;
  1562. case WM_DEVICECHANGE:
  1563. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE");
  1564. if (gDebugWindowProc)
  1565. {
  1566. llinfos << " WM_DEVICECHANGE: wParam=" << w_param
  1567. << "; lParam=" << l_param << llendl;
  1568. }
  1569. if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
  1570. {
  1571. if (window_imp->mCallbacks->handleDeviceChange(window_imp))
  1572. {
  1573. return 0;
  1574. }
  1575. }
  1576. break;
  1577. case WM_PAINT:
  1578. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT");
  1579. GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
  1580. update_width = update_rect.right - update_rect.left + 1;
  1581. update_height = update_rect.bottom - update_rect.top + 1;
  1582. window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
  1583. update_width, update_height);
  1584. break;
  1585. case WM_PARENTNOTIFY:
  1586. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY");
  1587. u_msg = u_msg;
  1588. break;
  1589. case WM_SETCURSOR:
  1590. // This message is sent whenever the cursor is moved in a window.
  1591. // You need to set the appropriate cursor appearance.
  1592. // Only take control of cursor over client region of window
  1593. // This allows Windows(tm) to handle resize cursors, etc.
  1594. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR");
  1595. if (LOWORD(l_param) == HTCLIENT)
  1596. {
  1597. SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] );
  1598. return 0;
  1599. }
  1600. break;
  1601. case WM_ENTERMENULOOP:
  1602. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP");
  1603. window_imp->mCallbacks->handleWindowBlock(window_imp);
  1604. break;
  1605. case WM_EXITMENULOOP:
  1606. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP");
  1607. window_imp->mCallbacks->handleWindowUnblock(window_imp);
  1608. break;
  1609. case WM_ACTIVATEAPP:
  1610. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP");
  1611. {
  1612. // This message should be sent whenever the app gains or loses focus.
  1613. BOOL activating = (BOOL) w_param;
  1614. BOOL minimized = window_imp->getMinimized();
  1615. if (gDebugWindowProc)
  1616. {
  1617. LL_INFOS("Window") << "WINDOWPROC ActivateApp "
  1618. << " activating " << S32(activating)
  1619. << " minimized " << S32(minimized)
  1620. << " fullscreen " << S32(window_imp->mFullscreen)
  1621. << LL_ENDL;
  1622. }
  1623. if (window_imp->mFullscreen)
  1624. {
  1625. // When we run fullscreen, restoring or minimizing the app needs
  1626. // to switch the screen resolution
  1627. if (activating)
  1628. {
  1629. window_imp->setFullscreenResolution();
  1630. window_imp->restore();
  1631. }
  1632. else
  1633. {
  1634. window_imp->minimize();
  1635. window_imp->resetDisplayResolution();
  1636. }
  1637. }
  1638. window_imp->mCallbacks->handleActivateApp(window_imp, activating);
  1639. break;
  1640. }
  1641. case WM_ACTIVATE:
  1642. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE");
  1643. {
  1644. // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
  1645. BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
  1646. BOOL minimized = BOOL(HIWORD(w_param));
  1647. if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
  1648. {
  1649. window_imp->interruptLanguageTextInput();
  1650. }
  1651. // JC - I'm not sure why, but if we don't report that we handled the
  1652. // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work
  1653. // properly when we run fullscreen.
  1654. if (gDebugWindowProc)
  1655. {
  1656. LL_INFOS("Window") << "WINDOWPROC Activate "
  1657. << " activating " << S32(activating)
  1658. << " minimized " << S32(minimized)
  1659. << LL_ENDL;
  1660. }
  1661. // Don't handle this.
  1662. break;
  1663. }
  1664. case WM_QUERYOPEN:
  1665. // TODO: use this to return a nice icon
  1666. break;
  1667. case WM_SYSCOMMAND:
  1668. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND");
  1669. switch(w_param)
  1670. {
  1671. case SC_KEYMENU:
  1672. // Disallow the ALT key from triggering the default system menu.
  1673. return 0;
  1674. case SC_SCREENSAVE:
  1675. case SC_MONITORPOWER:
  1676. // eat screen save messages and prevent them!
  1677. return 0;
  1678. }
  1679. break;
  1680. case WM_CLOSE:
  1681. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE");
  1682. // Will the app allow the window to close?
  1683. if (window_imp->mCallbacks->handleCloseRequest(window_imp))
  1684. {
  1685. // Get the app to initiate cleanup.
  1686. window_imp->mCallbacks->handleQuit(window_imp);
  1687. // The app is responsible for calling destroyWindow when done with GL
  1688. }
  1689. return 0;
  1690. case WM_DESTROY:
  1691. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY");
  1692. if (window_imp->shouldPostQuit())
  1693. {
  1694. PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0
  1695. }
  1696. return 0;
  1697. case WM_COMMAND:
  1698. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND");
  1699. if (!HIWORD(w_param)) // this message is from a menu
  1700. {
  1701. window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param));
  1702. }
  1703. break;
  1704. case WM_SYSKEYDOWN:
  1705. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN");
  1706. // allow system keys, such as ALT-F4 to be processed by Windows
  1707. eat_keystroke = FALSE;
  1708. case WM_KEYDOWN:
  1709. window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
  1710. window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
  1711. window_imp->mKeyVirtualKey = w_param;
  1712. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
  1713. {
  1714. if (gDebugWindowProc)
  1715. {
  1716. LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
  1717. << " key " << S32(w_param)
  1718. << LL_ENDL;
  1719. }
  1720. if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke)
  1721. {
  1722. return 0;
  1723. }
  1724. // pass on to windows if we didn't handle it
  1725. break;
  1726. }
  1727. case WM_SYSKEYUP:
  1728. eat_keystroke = FALSE;
  1729. case WM_KEYUP:
  1730. {
  1731. window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
  1732. window_imp->mKeyVirtualKey = w_param;
  1733. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
  1734. LLFastTimer t2(FTM_KEYHANDLER);
  1735. if (gDebugWindowProc)
  1736. {
  1737. LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
  1738. << " key " << S32(w_param)
  1739. << LL_ENDL;
  1740. }
  1741. if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke)
  1742. {
  1743. return 0;
  1744. }
  1745. // pass on to windows
  1746. break;
  1747. }
  1748. case WM_IME_SETCONTEXT:
  1749. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT");
  1750. if (gDebugWindowProc)
  1751. {
  1752. llinfos << "WM_IME_SETCONTEXT" << llendl;
  1753. }
  1754. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1755. {
  1756. l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
  1757. // Invoke DefWinProc with the modified LPARAM.
  1758. }
  1759. break;
  1760. case WM_IME_STARTCOMPOSITION:
  1761. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION");
  1762. if (gDebugWindowProc)
  1763. {
  1764. llinfos << "WM_IME_STARTCOMPOSITION" << llendl;
  1765. }
  1766. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1767. {
  1768. window_imp->handleStartCompositionMessage();
  1769. return 0;
  1770. }
  1771. break;
  1772. case WM_IME_ENDCOMPOSITION:
  1773. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION");
  1774. if (gDebugWindowProc)
  1775. {
  1776. llinfos << "WM_IME_ENDCOMPOSITION" << llendl;
  1777. }
  1778. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1779. {
  1780. return 0;
  1781. }
  1782. break;
  1783. case WM_IME_COMPOSITION:
  1784. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION");
  1785. if (gDebugWindowProc)
  1786. {
  1787. llinfos << "WM_IME_COMPOSITION" << llendl;
  1788. }
  1789. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1790. {
  1791. window_imp->handleCompositionMessage(l_param);
  1792. return 0;
  1793. }
  1794. break;
  1795. case WM_IME_REQUEST:
  1796. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
  1797. if (gDebugWindowProc)
  1798. {
  1799. llinfos << "WM_IME_REQUEST" << llendl;
  1800. }
  1801. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1802. {
  1803. LRESULT result = 0;
  1804. if (window_imp->handleImeRequests(w_param, l_param, &result))
  1805. {
  1806. return result;
  1807. }
  1808. }
  1809. break;
  1810. case WM_CHAR:
  1811. window_imp->mKeyCharCode = w_param;
  1812. // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
  1813. // to figure out how that works. - Doug
  1814. //
  1815. // ... Well, I don't think so.
  1816. // How it works is explained in Win32 API document, but WM_UNICHAR didn't work
  1817. // as specified at least on Windows XP SP1 Japanese version. I have never used
  1818. // it since then, and I'm not sure whether it has been fixed now, but I don't think
  1819. // it is worth trying. The good old WM_CHAR works just fine even for supplementary
  1820. // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's
  1821. // by ourselves. It is not that tough. -- Alissa Sabre @ SL
  1822. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
  1823. if (gDebugWindowProc)
  1824. {
  1825. LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
  1826. << " key " << S32(w_param)
  1827. << LL_ENDL;
  1828. }
  1829. // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
  1830. // we *did* processed the event, so I believe we should not pass it to DefWindowProc...
  1831. window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
  1832. return 0;
  1833. case WM_LBUTTONDOWN:
  1834. {
  1835. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
  1836. LLFastTimer t2(FTM_MOUSEHANDLER);
  1837. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1838. {
  1839. window_imp->interruptLanguageTextInput();
  1840. }
  1841. // Because we move the cursor position in the app, we need to query
  1842. // to find out where the cursor at the time the event is handled.
  1843. // If we don't do this, many clicks could get buffered up, and if the
  1844. // first click changes the cursor position, all subsequent clicks
  1845. // will occur at the wrong location. JC
  1846. LLCoordWindow cursor_coord_window;
  1847. if (window_imp->mMousePositionModified)
  1848. {
  1849. window_imp->getCursorPosition(&cursor_coord_window);
  1850. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1851. }
  1852. else
  1853. {
  1854. window_imp->convertCoords(window_coord, &gl_coord);
  1855. }
  1856. MASK mask = gKeyboard->currentMask(TRUE);
  1857. // generate move event to update mouse coordinates
  1858. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1859. if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
  1860. {
  1861. return 0;
  1862. }
  1863. }
  1864. break;
  1865. case WM_LBUTTONDBLCLK:
  1866. //RN: ignore right button double clicks for now
  1867. //case WM_RBUTTONDBLCLK:
  1868. {
  1869. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK");
  1870. // Because we move the cursor position in the app, we need to query
  1871. // to find out where the cursor at the time the event is handled.
  1872. // If we don't do this, many clicks could get buffered up, and if the
  1873. // first click changes the cursor position, all subsequent clicks
  1874. // will occur at the wrong location. JC
  1875. LLCoordWindow cursor_coord_window;
  1876. if (window_imp->mMousePositionModified)
  1877. {
  1878. window_imp->getCursorPosition(&cursor_coord_window);
  1879. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1880. }
  1881. else
  1882. {
  1883. window_imp->convertCoords(window_coord, &gl_coord);
  1884. }
  1885. MASK mask = gKeyboard->currentMask(TRUE);
  1886. // generate move event to update mouse coordinates
  1887. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1888. if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) )
  1889. {
  1890. return 0;
  1891. }
  1892. }
  1893. break;
  1894. case WM_LBUTTONUP:
  1895. {
  1896. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
  1897. LLFastTimer t2(FTM_MOUSEHANDLER);
  1898. //if (gDebugClicks)
  1899. //{
  1900. // LL_INFOS("Window") << "WndProc left button up" << LL_ENDL;
  1901. //}
  1902. // Because we move the cursor position in the app, we need to query
  1903. // to find out where the cursor at the time the event is handled.
  1904. // If we don't do this, many clicks could get buffered up, and if the
  1905. // first click changes the cursor position, all subsequent clicks
  1906. // will occur at the wrong location. JC
  1907. LLCoordWindow cursor_coord_window;
  1908. if (window_imp->mMousePositionModified)
  1909. {
  1910. window_imp->getCursorPosition(&cursor_coord_window);
  1911. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1912. }
  1913. else
  1914. {
  1915. window_imp->convertCoords(window_coord, &gl_coord);
  1916. }
  1917. MASK mask = gKeyboard->currentMask(TRUE);
  1918. // generate move event to update mouse coordinates
  1919. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1920. if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask))
  1921. {
  1922. return 0;
  1923. }
  1924. }
  1925. break;
  1926. case WM_RBUTTONDBLCLK:
  1927. case WM_RBUTTONDOWN:
  1928. {
  1929. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN");
  1930. LLFastTimer t2(FTM_MOUSEHA