llwindowwin32.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:103k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llwindowwin32.cpp
  3.  * @brief Platform-dependent implementation of llwindow
  4.  *
  5.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2001-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #if LL_WINDOWS && !LL_MESA_HEADLESS
  34. #include "llwindowwin32.h"
  35. // LLWindow library includes
  36. #include "llkeyboardwin32.h"
  37. #include "lldragdropwin32.h"
  38. #include "llpreeditor.h"
  39. #include "llwindowcallbacks.h"
  40. // Linden library includes
  41. #include "llerror.h"
  42. #include "llgl.h"
  43. #include "llstring.h"
  44. // System includes
  45. #include <commdlg.h>
  46. #include <WinUser.h>
  47. #include <mapi.h>
  48. #include <process.h> // for _spawn
  49. #include <shellapi.h>
  50. #include <fstream>
  51. #include <Imm.h>
  52. // Require DirectInput version 8
  53. #define DIRECTINPUT_VERSION 0x0800
  54. #include <dinput.h>
  55. #include <Dbt.h.>
  56. #include "llmemtype.h"
  57. // culled from winuser.h
  58. #ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */
  59. const S32 WM_MOUSEWHEEL = 0x020A;
  60. #endif
  61. #ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */
  62. const S32 WHEEL_DELTA = 120;     /* Value for rolling one detent */
  63. #endif
  64. const S32 MAX_MESSAGE_PER_UPDATE = 20;
  65. const S32 BITS_PER_PIXEL = 32;
  66. const S32 MAX_NUM_RESOLUTIONS = 32;
  67. const F32 ICON_FLASH_TIME = 0.5f;
  68. extern BOOL gDebugWindowProc;
  69. LPWSTR gIconResource = IDI_APPLICATION;
  70. LLW32MsgCallback gAsyncMsgCallback = NULL;
  71. //
  72. // LLWindowWin32
  73. //
  74. void show_window_creation_error(const std::string& title)
  75. {
  76. LL_WARNS("Window") << title << LL_ENDL;
  77. }
  78. //static
  79. BOOL LLWindowWin32::sIsClassRegistered = FALSE;
  80. BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE;
  81. BOOL LLWindowWin32::sWinIMEOpened = FALSE;
  82. HKL LLWindowWin32::sWinInputLocale = 0;
  83. DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE;
  84. DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
  85. LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
  86. // The following class LLWinImm delegates Windows IMM APIs.
  87. // We need this because some language versions of Windows,
  88. // e.g., US version of Windows XP, doesn't install IMM32.DLL
  89. // as a default, and we can't link against imm32.lib statically.
  90. // I believe DLL loading of this type is best suited to do
  91. // in a static initialization of a class.  What I'm not sure is
  92. // whether it follows the Linden Conding Standard... 
  93. // See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
  94. class LLWinImm
  95. {
  96. public:
  97. static bool isAvailable() { return sTheInstance.mHImmDll != NULL; }
  98. public:
  99. // Wrappers for IMM API.
  100. static BOOL isIME(HKL hkl);
  101. static HWND getDefaultIMEWnd(HWND hwnd);
  102. static HIMC getContext(HWND hwnd);
  103. static BOOL releaseContext(HWND hwnd, HIMC himc);
  104. static BOOL getOpenStatus(HIMC himc);
  105. static BOOL setOpenStatus(HIMC himc, BOOL status);
  106. static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence);
  107. static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);
  108. static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);
  109. static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);
  110. static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length);
  111. static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength);
  112. static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont);
  113. static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
  114. static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
  115. private:
  116. LLWinImm();
  117. ~LLWinImm();
  118. private:
  119. // Pointers to IMM API.
  120. BOOL   (WINAPI *mImmIsIME)(HKL);
  121. HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND);
  122. HIMC (WINAPI *mImmGetContext)(HWND);
  123. BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC);
  124. BOOL (WINAPI *mImmGetOpenStatus)(HIMC);
  125. BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
  126. BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
  127. BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
  128. BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
  129. BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
  130. LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
  131. BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
  132. BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
  133. BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
  134. BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
  135. private:
  136. HMODULE mHImmDll;
  137. static LLWinImm sTheInstance;
  138. };
  139. LLWinImm LLWinImm::sTheInstance;
  140. LLWinImm::LLWinImm() : mHImmDll(NULL)
  141. {
  142. // Check system metrics 
  143. if ( !GetSystemMetrics( SM_DBCSENABLED ) )
  144. return;
  145. mHImmDll = LoadLibraryA("Imm32");
  146. if (mHImmDll != NULL)
  147. {
  148. mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
  149. mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
  150. mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
  151. mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
  152. mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
  153. mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
  154. mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
  155. mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
  156. mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
  157. mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
  158. mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
  159. mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
  160. mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
  161. mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
  162. mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME");
  163. if (mImmIsIME == NULL ||
  164. mImmGetDefaultIMEWnd == NULL ||
  165. mImmGetContext == NULL ||
  166. mImmReleaseContext == NULL ||
  167. mImmGetOpenStatus == NULL ||
  168. mImmSetOpenStatus == NULL ||
  169. mImmGetConversionStatus == NULL ||
  170. mImmSetConversionStatus == NULL ||
  171. mImmGetCompostitionWindow == NULL ||
  172. mImmSetCompostitionWindow == NULL ||
  173. mImmGetCompositionString == NULL ||
  174. mImmSetCompositionString == NULL ||
  175. mImmSetCompositionFont == NULL ||
  176. mImmSetCandidateWindow == NULL ||
  177. mImmNotifyIME == NULL)
  178. {
  179. // If any of the above API entires are not found, we can't use IMM API.  
  180. // So, turn off the IMM support.  We should log some warning message in 
  181. // the case, since it is very unusual; these APIs are available from 
  182. // the beginning, and all versions of IMM32.DLL should have them all.  
  183. // Unfortunately, this code may be executed before initialization of 
  184. // the logging channel (llwarns), and we can't do it here...  Yes, this 
  185. // is one of disadvantages to use static constraction to DLL loading. 
  186. FreeLibrary(mHImmDll);
  187. mHImmDll = NULL;
  188. // If we unload the library, make sure all the function pointers are cleared
  189. mImmIsIME = NULL;
  190. mImmGetDefaultIMEWnd = NULL;
  191. mImmGetContext = NULL;
  192. mImmReleaseContext = NULL;
  193. mImmGetOpenStatus = NULL;
  194. mImmSetOpenStatus = NULL;
  195. mImmGetConversionStatus = NULL;
  196. mImmSetConversionStatus = NULL;
  197. mImmGetCompostitionWindow = NULL;
  198. mImmSetCompostitionWindow = NULL;
  199. mImmGetCompositionString = NULL;
  200. mImmSetCompositionString = NULL;
  201. mImmSetCompositionFont = NULL;
  202. mImmSetCandidateWindow = NULL;
  203. mImmNotifyIME = NULL;
  204. }
  205. }
  206. }
  207. // static 
  208. BOOL LLWinImm::isIME(HKL hkl)
  209. if ( sTheInstance.mImmIsIME )
  210. return sTheInstance.mImmIsIME(hkl); 
  211. return FALSE;
  212. }
  213. // static 
  214. HIMC LLWinImm::getContext(HWND hwnd)
  215. {
  216. if ( sTheInstance.mImmGetContext )
  217. return sTheInstance.mImmGetContext(hwnd); 
  218. return 0;
  219. }
  220. //static 
  221. BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc)
  222. if ( sTheInstance.mImmIsIME )
  223. return sTheInstance.mImmReleaseContext(hwnd, himc); 
  224. return FALSE;
  225. }
  226. // static 
  227. BOOL LLWinImm::getOpenStatus(HIMC himc)
  228. if ( sTheInstance.mImmGetOpenStatus )
  229. return sTheInstance.mImmGetOpenStatus(himc); 
  230. return FALSE;
  231. }
  232. // static 
  233. BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status)
  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. if ( sTheInstance.mImmGetConversionStatus )
  241. return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
  242. return FALSE;
  243. }
  244. // static 
  245. BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)
  246. if ( sTheInstance.mImmSetConversionStatus )
  247. return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
  248. return FALSE;
  249. }
  250. // static 
  251. BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)
  252. if ( sTheInstance.mImmGetCompostitionWindow )
  253. return sTheInstance.mImmGetCompostitionWindow(himc, form);
  254. return FALSE;
  255. }
  256. // static 
  257. BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)
  258. if ( sTheInstance.mImmSetCompostitionWindow )
  259. return sTheInstance.mImmSetCompostitionWindow(himc, form);
  260. return FALSE;
  261. }
  262. // static 
  263. LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)
  264. if ( sTheInstance.mImmGetCompositionString )
  265. return sTheInstance.mImmGetCompositionString(himc, index, data, length);
  266. return FALSE;
  267. }
  268. // static 
  269. BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)
  270. if ( sTheInstance.mImmSetCompositionString )
  271. return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);
  272. return FALSE;
  273. }
  274. // static 
  275. BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)
  276. if ( sTheInstance.mImmSetCompositionFont )
  277. return sTheInstance.mImmSetCompositionFont(himc, pFont);
  278. return FALSE;
  279. }
  280. // static 
  281. BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)
  282. if ( sTheInstance.mImmSetCandidateWindow )
  283. return sTheInstance.mImmSetCandidateWindow(himc, form);
  284. return FALSE;
  285. }
  286. // static 
  287. BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)
  288. if ( sTheInstance.mImmNotifyIME )
  289. return sTheInstance.mImmNotifyIME(himc, action, index, value);
  290. return FALSE;
  291. }
  292. // ----------------------------------------------------------------------------------------
  293. LLWinImm::~LLWinImm()
  294. {
  295. if (mHImmDll != NULL)
  296. {
  297. FreeLibrary(mHImmDll);
  298. mHImmDll = NULL;
  299. }
  300. }
  301. LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
  302.  const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
  303.  S32 height, U32 flags, 
  304.  BOOL fullscreen, BOOL clearBg,
  305.  BOOL disable_vsync, BOOL use_gl,
  306.  BOOL ignore_pixel_depth,
  307.  U32 fsaa_samples)
  308. : LLWindow(callbacks, fullscreen, flags)
  309. {
  310. mFSAASamples = fsaa_samples;
  311. mIconResource = gIconResource;
  312. mOverrideAspectRatio = 0.f;
  313. mNativeAspectRatio = 0.f;
  314. mMousePositionModified = FALSE;
  315. mInputProcessingPaused = FALSE;
  316. mPreeditor = NULL;
  317. mKeyCharCode = 0;
  318. mKeyScanCode = 0;
  319. mKeyVirtualKey = 0;
  320. mhDC = NULL;
  321. mhRC = NULL;
  322. // Initialize the keyboard
  323. gKeyboard = new LLKeyboardWin32();
  324. gKeyboard->setCallbacks(callbacks);
  325. // Initialize the Drag and Drop functionality
  326. mDragDrop = new LLDragDropWin32;
  327. // Initialize (boot strap) the Language text input management,
  328. // based on the system's (user's) default settings.
  329. allowLanguageTextInput(mPreeditor, FALSE);
  330. WNDCLASS wc;
  331. RECT window_rect;
  332. // Set the window title
  333. if (title.empty())
  334. {
  335. mWindowTitle = new WCHAR[50];
  336. wsprintf(mWindowTitle, L"OpenGL Window");
  337. }
  338. else
  339. {
  340. mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars.
  341. mbstowcs(mWindowTitle, title.c_str(), 255);
  342. mWindowTitle[255] = 0;
  343. }
  344. // Set the window class name
  345. if (name.empty())
  346. {
  347. mWindowClassName = new WCHAR[50];
  348. wsprintf(mWindowClassName, L"OpenGL Window");
  349. }
  350. else
  351. {
  352. mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars.
  353. mbstowcs(mWindowClassName, name.c_str(), 255);
  354. mWindowClassName[255] = 0;
  355. }
  356. // We're not clipping yet
  357. SetRect( &mOldMouseClip, 0, 0, 0, 0 );
  358. // Make an instance of our window then define the window class
  359. mhInstance = GetModuleHandle(NULL);
  360. mWndProc = NULL;
  361. mSwapMethod = SWAP_METHOD_UNDEFINED;
  362. // No WPARAM yet.
  363. mLastSizeWParam = 0;
  364. // Windows GDI rects don't include rightmost pixel
  365. window_rect.left = (long) 0;
  366. window_rect.right = (long) width;
  367. window_rect.top = (long) 0;
  368. window_rect.bottom = (long) height;
  369. // Grab screen size to sanitize the window
  370. S32 window_border_y = GetSystemMetrics(SM_CYBORDER);
  371. S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); 
  372. S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); 
  373. S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  374. S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  375. if (x < virtual_screen_x) x = virtual_screen_x;
  376. if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y;
  377. if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width;
  378. if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height;
  379. if (!sIsClassRegistered)
  380. {
  381. // Force redraw when resized and create a private device context
  382. // Makes double click messages.
  383. wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
  384. // Set message handler function
  385. wc.lpfnWndProc = (WNDPROC) mainWindowProc;
  386. // unused
  387. wc.cbClsExtra = 0;
  388. wc.cbWndExtra = 0;
  389. wc.hInstance = mhInstance;
  390. wc.hIcon = LoadIcon(mhInstance, mIconResource);
  391. // We will set the cursor ourselves
  392. wc.hCursor = NULL;
  393. // background color is not used
  394. if (clearBg)
  395. {
  396. wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  397. }
  398. else
  399. {
  400. wc.hbrBackground = (HBRUSH) NULL;
  401. }
  402. // we don't use windows menus
  403. wc.lpszMenuName = NULL;
  404. wc.lpszClassName = mWindowClassName;
  405. if (!RegisterClass(&wc))
  406. {
  407. OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), 
  408. mCallbacks->translateString("MBError"), OSMB_OK);
  409. return;
  410. }
  411. sIsClassRegistered = TRUE;
  412. }
  413. //-----------------------------------------------------------------------
  414. // Get the current refresh rate
  415. //-----------------------------------------------------------------------
  416. DEVMODE dev_mode;
  417. DWORD current_refresh;
  418. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  419. {
  420. current_refresh = dev_mode.dmDisplayFrequency;
  421. mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight);
  422. }
  423. else
  424. {
  425. current_refresh = 60;
  426. }
  427. //-----------------------------------------------------------------------
  428. // Drop resolution and go fullscreen
  429. // use a display mode with our desired size and depth, with a refresh
  430. // rate as close at possible to the users' default
  431. //-----------------------------------------------------------------------
  432. if (mFullscreen)
  433. {
  434. BOOL success = FALSE;
  435. DWORD closest_refresh = 0;
  436. for (S32 mode_num = 0;; mode_num++)
  437. {
  438. if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
  439. {
  440. break;
  441. }
  442. if (dev_mode.dmPelsWidth == width &&
  443. dev_mode.dmPelsHeight == height &&
  444. dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
  445. {
  446. success = TRUE;
  447. if ((dev_mode.dmDisplayFrequency - current_refresh)
  448. < (closest_refresh - current_refresh))
  449. {
  450. closest_refresh = dev_mode.dmDisplayFrequency;
  451. }
  452. }
  453. }
  454. if (closest_refresh == 0)
  455. {
  456. LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
  457. success = FALSE;
  458. }
  459. // If we found a good resolution, use it.
  460. if (success)
  461. {
  462. success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
  463. }
  464. // Keep a copy of the actual current device mode in case we minimize 
  465. // and change the screen resolution.   JC
  466. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
  467. // If it failed, we don't want to run fullscreen
  468. if (success)
  469. {
  470. mFullscreen = TRUE;
  471. mFullscreenWidth   = dev_mode.dmPelsWidth;
  472. mFullscreenHeight  = dev_mode.dmPelsHeight;
  473. mFullscreenBits    = dev_mode.dmBitsPerPel;
  474. mFullscreenRefresh = dev_mode.dmDisplayFrequency;
  475. LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
  476. << "x"   << dev_mode.dmPelsHeight
  477. << "x"   << dev_mode.dmBitsPerPel
  478. << " @ " << dev_mode.dmDisplayFrequency
  479. << LL_ENDL;
  480. }
  481. else
  482. {
  483. mFullscreen = FALSE;
  484. mFullscreenWidth   = -1;
  485. mFullscreenHeight  = -1;
  486. mFullscreenBits    = -1;
  487. mFullscreenRefresh = -1;
  488. std::map<std::string,std::string> args;
  489. args["[WIDTH]"] = llformat("%d", width);
  490. args["[HEIGHT]"] = llformat ("%d", height);
  491. OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args),
  492. mCallbacks->translateString("MBError"), OSMB_OK);
  493. }
  494. }
  495. // TODO: add this after resolving _WIN32_WINNT issue
  496. // if (!fullscreen)
  497. // {
  498. // TRACKMOUSEEVENT track_mouse_event;
  499. // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
  500. // track_mouse_event.dwFlags = TME_LEAVE;
  501. // track_mouse_event.hwndTrack = mWindowHandle;
  502. // track_mouse_event.dwHoverTime = HOVER_DEFAULT;
  503. // TrackMouseEvent( &track_mouse_event ); 
  504. // }
  505. //-----------------------------------------------------------------------
  506. // Create GL drawing context
  507. //-----------------------------------------------------------------------
  508. LLCoordScreen windowPos(x,y);
  509. LLCoordScreen windowSize(window_rect.right - window_rect.left,
  510.  window_rect.bottom - window_rect.top);
  511. if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos))
  512. {
  513. return;
  514. }
  515. //start with arrow cursor
  516. initCursors();
  517. setCursor( UI_CURSOR_ARROW );
  518. // Initialize (boot strap) the Language text input management,
  519. // based on the system's (or user's) default settings.
  520. allowLanguageTextInput(NULL, FALSE);
  521. }
  522. LLWindowWin32::~LLWindowWin32()
  523. {
  524. delete mDragDrop;
  525. delete [] mWindowTitle;
  526. mWindowTitle = NULL;
  527. delete [] mSupportedResolutions;
  528. mSupportedResolutions = NULL;
  529. delete mWindowClassName;
  530. mWindowClassName = NULL;
  531. }
  532. void LLWindowWin32::show()
  533. {
  534. ShowWindow(mWindowHandle, SW_SHOW);
  535. SetForegroundWindow(mWindowHandle);
  536. SetFocus(mWindowHandle);
  537. }
  538. void LLWindowWin32::hide()
  539. {
  540. setMouseClipping(FALSE);
  541. ShowWindow(mWindowHandle, SW_HIDE);
  542. }
  543. //virtual
  544. void LLWindowWin32::minimize()
  545. {
  546. setMouseClipping(FALSE);
  547. showCursor();
  548. ShowWindow(mWindowHandle, SW_MINIMIZE);
  549. }
  550. //virtual
  551. void LLWindowWin32::restore()
  552. {
  553. ShowWindow(mWindowHandle, SW_RESTORE);
  554. SetForegroundWindow(mWindowHandle);
  555. SetFocus(mWindowHandle);
  556. }
  557. // close() destroys all OS-specific code associated with a window.
  558. // Usually called from LLWindowManager::destroyWindow()
  559. void LLWindowWin32::close()
  560. {
  561. LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL;
  562. // Is window is already closed?
  563. if (!mWindowHandle)
  564. {
  565. return;
  566. }
  567. mDragDrop->reset();
  568. // Make sure cursor is visible and we haven't mangled the clipping state.
  569. setMouseClipping(FALSE);
  570. showCursor();
  571. // Go back to screen mode written in the registry.
  572. if (mFullscreen)
  573. {
  574. resetDisplayResolution();
  575. }
  576. // Clean up remaining GL state
  577. LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL;
  578. gGLManager.shutdownGL();
  579. LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL;
  580. if (mhRC)
  581. {
  582. if (!wglMakeCurrent(NULL, NULL))
  583. {
  584. LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
  585. }
  586. if (!wglDeleteContext(mhRC))
  587. {
  588. LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
  589. }
  590. mhRC = NULL;
  591. }
  592. // Restore gamma to the system values.
  593. restoreGamma();
  594. if (mhDC && !ReleaseDC(mWindowHandle, mhDC))
  595. {
  596. LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
  597. mhDC = NULL;
  598. }
  599. LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
  600. // Don't process events in our mainWindowProc any longer.
  601. SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
  602. // Make sure we don't leave a blank toolbar button.
  603. ShowWindow(mWindowHandle, SW_HIDE);
  604. // This causes WM_DESTROY to be sent *immediately*
  605. if (!DestroyWindow(mWindowHandle))
  606. {
  607. OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
  608. mCallbacks->translateString("MBShutdownErr"),
  609. OSMB_OK);
  610. }
  611. mWindowHandle = NULL;
  612. }
  613. BOOL LLWindowWin32::isValid()
  614. {
  615. return (mWindowHandle != NULL);
  616. }
  617. BOOL LLWindowWin32::getVisible()
  618. {
  619. return (mWindowHandle && IsWindowVisible(mWindowHandle));
  620. }
  621. BOOL LLWindowWin32::getMinimized()
  622. {
  623. return (mWindowHandle && IsIconic(mWindowHandle));
  624. }
  625. BOOL LLWindowWin32::getMaximized()
  626. {
  627. return (mWindowHandle && IsZoomed(mWindowHandle));
  628. }
  629. BOOL LLWindowWin32::maximize()
  630. {
  631. BOOL success = FALSE;
  632. if (!mWindowHandle) return success;
  633. WINDOWPLACEMENT placement;
  634. placement.length = sizeof(WINDOWPLACEMENT);
  635. success = GetWindowPlacement(mWindowHandle, &placement);
  636. if (!success) return success;
  637. placement.showCmd = SW_MAXIMIZE;
  638. success = SetWindowPlacement(mWindowHandle, &placement);
  639. return success;
  640. }
  641. BOOL LLWindowWin32::getFullscreen()
  642. {
  643. return mFullscreen;
  644. }
  645. BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
  646. {
  647. RECT window_rect;
  648. if (!mWindowHandle ||
  649. !GetWindowRect(mWindowHandle, &window_rect) ||
  650. NULL == position)
  651. {
  652. return FALSE;
  653. }
  654. position->mX = window_rect.left;
  655. position->mY = window_rect.top;
  656. return TRUE;
  657. }
  658. BOOL LLWindowWin32::getSize(LLCoordScreen *size)
  659. {
  660. RECT window_rect;
  661. if (!mWindowHandle ||
  662. !GetWindowRect(mWindowHandle, &window_rect) ||
  663. NULL == size)
  664. {
  665. return FALSE;
  666. }
  667. size->mX = window_rect.right - window_rect.left;
  668. size->mY = window_rect.bottom - window_rect.top;
  669. return TRUE;
  670. }
  671. BOOL LLWindowWin32::getSize(LLCoordWindow *size)
  672. {
  673. RECT client_rect;
  674. if (!mWindowHandle ||
  675. !GetClientRect(mWindowHandle, &client_rect) ||
  676. NULL == size)
  677. {
  678. return FALSE;
  679. }
  680. size->mX = client_rect.right - client_rect.left;
  681. size->mY = client_rect.bottom - client_rect.top;
  682. return TRUE;
  683. }
  684. BOOL LLWindowWin32::setPosition(const LLCoordScreen position)
  685. {
  686. LLCoordScreen size;
  687. if (!mWindowHandle)
  688. {
  689. return FALSE;
  690. }
  691. getSize(&size);
  692. moveWindow(position, size);
  693. return TRUE;
  694. }
  695. BOOL LLWindowWin32::setSize(const LLCoordScreen size)
  696. {
  697. LLCoordScreen position;
  698. getPosition(&position);
  699. if (!mWindowHandle)
  700. {
  701. return FALSE;
  702. }
  703. moveWindow(position, size);
  704. return TRUE;
  705. }
  706. // changing fullscreen resolution
  707. BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
  708. {
  709. GLuint pixel_format;
  710. DEVMODE dev_mode;
  711. DWORD current_refresh;
  712. DWORD dw_ex_style;
  713. DWORD dw_style;
  714. RECT window_rect;
  715. S32 width = size.mX;
  716. S32 height = size.mY;
  717. BOOL auto_show = FALSE;
  718. if (mhRC)
  719. {
  720. auto_show = TRUE;
  721. resetDisplayResolution();
  722. }
  723. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  724. {
  725. current_refresh = dev_mode.dmDisplayFrequency;
  726. }
  727. else
  728. {
  729. current_refresh = 60;
  730. }
  731. gGLManager.shutdownGL();
  732. //destroy gl context
  733. if (mhRC)
  734. {
  735. if (!wglMakeCurrent(NULL, NULL))
  736. {
  737. LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
  738. }
  739. if (!wglDeleteContext(mhRC))
  740. {
  741. LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
  742. }
  743. mhRC = NULL;
  744. }
  745. if (fullscreen)
  746. {
  747. mFullscreen = TRUE;
  748. BOOL success = FALSE;
  749. DWORD closest_refresh = 0;
  750. for (S32 mode_num = 0;; mode_num++)
  751. {
  752. if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
  753. {
  754. break;
  755. }
  756. if (dev_mode.dmPelsWidth == width &&
  757. dev_mode.dmPelsHeight == height &&
  758. dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
  759. {
  760. success = TRUE;
  761. if ((dev_mode.dmDisplayFrequency - current_refresh)
  762. < (closest_refresh - current_refresh))
  763. {
  764. closest_refresh = dev_mode.dmDisplayFrequency;
  765. }
  766. }
  767. }
  768. if (closest_refresh == 0)
  769. {
  770. LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
  771. return FALSE;
  772. }
  773. // If we found a good resolution, use it.
  774. if (success)
  775. {
  776. success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
  777. }
  778. // Keep a copy of the actual current device mode in case we minimize 
  779. // and change the screen resolution.   JC
  780. EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
  781. if (success)
  782. {
  783. mFullscreen = TRUE;
  784. mFullscreenWidth   = dev_mode.dmPelsWidth;
  785. mFullscreenHeight  = dev_mode.dmPelsHeight;
  786. mFullscreenBits    = dev_mode.dmBitsPerPel;
  787. mFullscreenRefresh = dev_mode.dmDisplayFrequency;
  788. LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
  789. << "x"   << dev_mode.dmPelsHeight
  790. << "x"   << dev_mode.dmBitsPerPel
  791. << " @ " << dev_mode.dmDisplayFrequency
  792. << LL_ENDL;
  793. window_rect.left = (long) 0;
  794. window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel
  795. window_rect.top = (long) 0;
  796. window_rect.bottom = (long) height;
  797. dw_ex_style = WS_EX_APPWINDOW;
  798. dw_style = WS_POPUP;
  799. // Move window borders out not to cover window contents
  800. AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
  801. }
  802. // If it failed, we don't want to run fullscreen
  803. else
  804. {
  805. mFullscreen = FALSE;
  806. mFullscreenWidth   = -1;
  807. mFullscreenHeight  = -1;
  808. mFullscreenBits    = -1;
  809. mFullscreenRefresh = -1;
  810. LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
  811. return FALSE;
  812. }
  813. }
  814. else
  815. {
  816. mFullscreen = FALSE;
  817. window_rect.left = (long) (posp ? posp->mX : 0);
  818. window_rect.right = (long) width + window_rect.left; // Windows GDI rects don't include rightmost pixel
  819. window_rect.top = (long) (posp ? posp->mY : 0);
  820. window_rect.bottom = (long) height + window_rect.top;
  821. // Window with an edge
  822. dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  823. dw_style = WS_OVERLAPPEDWINDOW;
  824. }
  825. // don't post quit messages when destroying old windows
  826. mPostQuit = FALSE;
  827. // create window
  828. DestroyWindow(mWindowHandle);
  829. mWindowHandle = CreateWindowEx(dw_ex_style,
  830. mWindowClassName,
  831. mWindowTitle,
  832. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
  833. window_rect.left, // x pos
  834. window_rect.top, // y pos
  835. window_rect.right - window_rect.left, // width
  836. window_rect.bottom - window_rect.top, // height
  837. NULL,
  838. NULL,
  839. mhInstance,
  840. NULL);
  841. //-----------------------------------------------------------------------
  842. // Create GL drawing context
  843. //-----------------------------------------------------------------------
  844. static PIXELFORMATDESCRIPTOR pfd =
  845. {
  846. sizeof(PIXELFORMATDESCRIPTOR), 
  847. 1,
  848. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 
  849. PFD_TYPE_RGBA,
  850. BITS_PER_PIXEL,
  851. 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused
  852. 8, // alpha bits
  853. 0, // alpha shift
  854. 0, // accum bits
  855. 0, 0, 0, 0, // accum RGBA
  856. 24, // depth bits
  857. 8, // stencil bits, avi added for stencil test
  858. 0,
  859. PFD_MAIN_PLANE,
  860. 0,
  861. 0, 0, 0
  862. };
  863. if (!(mhDC = GetDC(mWindowHandle)))
  864. {
  865. close();
  866. OSMessageBox(mCallbacks->translateString("MBDevContextErr"),
  867. mCallbacks->translateString("MBError"), OSMB_OK);
  868. return FALSE;
  869. }
  870. if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
  871. {
  872. close();
  873. OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
  874. mCallbacks->translateString("MBError"), OSMB_OK);
  875. return FALSE;
  876. }
  877. // Verify what pixel format we actually received.
  878. if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
  879. &pfd))
  880. {
  881. close();
  882. OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"),
  883. mCallbacks->translateString("MBError"), OSMB_OK);
  884. return FALSE;
  885. }
  886. if (pfd.cColorBits < 32)
  887. {
  888. close();
  889. OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"),
  890. mCallbacks->translateString("MBError"), OSMB_OK);
  891. return FALSE;
  892. }
  893. if (pfd.cAlphaBits < 8)
  894. {
  895. close();
  896. OSMessageBox(mCallbacks->translateString("MBAlpha"),
  897. mCallbacks->translateString("MBError"), OSMB_OK);
  898. return FALSE;
  899. }
  900. if (!SetPixelFormat(mhDC, pixel_format, &pfd))
  901. {
  902. close();
  903. OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
  904. mCallbacks->translateString("MBError"), OSMB_OK);
  905. return FALSE;
  906. }
  907. if (!(mhRC = wglCreateContext(mhDC)))
  908. {
  909. close();
  910. OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
  911. mCallbacks->translateString("MBError"), OSMB_OK);
  912. return FALSE;
  913. }
  914. if (!wglMakeCurrent(mhDC, mhRC))
  915. {
  916. close();
  917. OSMessageBox(mCallbacks->translateString("MBGLContextActErr"),
  918. mCallbacks->translateString("MBError"), OSMB_OK);
  919. return FALSE;
  920. }
  921. gGLManager.initWGL();
  922. if (wglChoosePixelFormatARB)
  923. {
  924. // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we
  925. // can get exactly what we want.
  926. GLint attrib_list[256];
  927. S32 cur_attrib = 0;
  928. attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;
  929. attrib_list[cur_attrib++] = 24;
  930. attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB;
  931. attrib_list[cur_attrib++] = 8;
  932. attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;
  933. attrib_list[cur_attrib++] = GL_TRUE;
  934. attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB;
  935. attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB;
  936. attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB;
  937. attrib_list[cur_attrib++] = GL_TRUE;
  938. attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB;
  939. attrib_list[cur_attrib++] = GL_TRUE;
  940. attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
  941. attrib_list[cur_attrib++] = 24;
  942. attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
  943. attrib_list[cur_attrib++] = 8;
  944. U32 end_attrib = 0;
  945. if (mFSAASamples > 0)
  946. {
  947. end_attrib = cur_attrib;
  948. attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB;
  949. attrib_list[cur_attrib++] = GL_TRUE;
  950. attrib_list[cur_attrib++] = WGL_SAMPLES_ARB;
  951. attrib_list[cur_attrib++] = mFSAASamples;
  952. }
  953. // End the list
  954. attrib_list[cur_attrib++] = 0;
  955. GLint pixel_formats[256];
  956. U32 num_formats = 0;
  957. // First we try and get a 32 bit depth pixel format
  958. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  959. if (!result)
  960. {
  961. close();
  962. show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit");
  963. return FALSE;
  964. }
  965. if (!num_formats)
  966. {
  967. if (end_attrib > 0)
  968. {
  969. LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL;
  970. attrib_list[end_attrib] = 0;
  971. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  972. if (!result)
  973. {
  974. close();
  975. show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA");
  976. return FALSE;
  977. }
  978. }
  979. if (!num_formats)
  980. {
  981. LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL;
  982. // Try 24-bit format
  983. attrib_list[1] = 24;
  984. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  985. if (!result)
  986. {
  987. close();
  988. show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit");
  989. return FALSE;
  990. }
  991. if (!num_formats)
  992. {
  993. LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL;
  994. attrib_list[1] = 16;
  995. BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
  996. if (!result || !num_formats)
  997. {
  998. close();
  999. show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit");
  1000. return FALSE;
  1001. }
  1002. }
  1003. }
  1004. LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL;
  1005. }
  1006. S32 swap_method = 0;
  1007. S32 cur_format = num_formats-1;
  1008. GLint swap_query = WGL_SWAP_METHOD_ARB;
  1009. BOOL found_format = FALSE;
  1010. while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
  1011. {
  1012. if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0)
  1013. {
  1014. found_format = TRUE;
  1015. }
  1016. else
  1017. {
  1018. --cur_format;
  1019. }
  1020. }
  1021. pixel_format = pixel_formats[cur_format];
  1022. if (mhDC != 0) // Does The Window Have A Device Context?
  1023. {
  1024. wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero
  1025. if (mhRC != 0) // Does The Window Have A Rendering Context?
  1026. {
  1027. wglDeleteContext (mhRC); // Release The Rendering Context
  1028. mhRC = 0; // Zero The Rendering Context
  1029. }
  1030. ReleaseDC (mWindowHandle, mhDC); // Release The Device Context
  1031. mhDC = 0; // Zero The Device Context
  1032. }
  1033. DestroyWindow (mWindowHandle); // Destroy The Window
  1034. mWindowHandle = CreateWindowEx(dw_ex_style,
  1035. mWindowClassName,
  1036. mWindowTitle,
  1037. WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
  1038. window_rect.left, // x pos
  1039. window_rect.top, // y pos
  1040. window_rect.right - window_rect.left, // width
  1041. window_rect.bottom - window_rect.top, // height
  1042. NULL,
  1043. NULL,
  1044. mhInstance,
  1045. NULL);
  1046. if (!(mhDC = GetDC(mWindowHandle)))
  1047. {
  1048. close();
  1049. OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1050. return FALSE;
  1051. }
  1052. if (!SetPixelFormat(mhDC, pixel_format, &pfd))
  1053. {
  1054. close();
  1055. OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
  1056. mCallbacks->translateString("MBError"), OSMB_OK);
  1057. return FALSE;
  1058. }
  1059. if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
  1060. {
  1061. switch (swap_method)
  1062. {
  1063. case WGL_SWAP_EXCHANGE_ARB:
  1064. mSwapMethod = SWAP_METHOD_EXCHANGE;
  1065. LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL;
  1066. break;
  1067. case WGL_SWAP_COPY_ARB:
  1068. mSwapMethod = SWAP_METHOD_COPY;
  1069. LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL;
  1070. break;
  1071. case WGL_SWAP_UNDEFINED_ARB:
  1072. mSwapMethod = SWAP_METHOD_UNDEFINED;
  1073. LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL;
  1074. break;
  1075. default:
  1076. mSwapMethod = SWAP_METHOD_UNDEFINED;
  1077. LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL;
  1078. break;
  1079. }
  1080. }
  1081. }
  1082. else
  1083. {
  1084. LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL;
  1085. }
  1086. // Verify what pixel format we actually received.
  1087. if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
  1088. &pfd))
  1089. {
  1090. close();
  1091. OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1092. return FALSE;
  1093. }
  1094. LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) 
  1095. << " Alpha Bits " << S32(pfd.cAlphaBits)
  1096. << " Depth Bits " << S32(pfd.cDepthBits) 
  1097. << LL_ENDL;
  1098. // make sure we have 32 bits per pixel
  1099. if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32)
  1100. {
  1101. close();
  1102. OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK);
  1103. return FALSE;
  1104. }
  1105. if (pfd.cAlphaBits < 8)
  1106. {
  1107. close();
  1108. OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK);
  1109. return FALSE;
  1110. }
  1111. if (!(mhRC = wglCreateContext(mhDC)))
  1112. {
  1113. close();
  1114. OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1115. return FALSE;
  1116. }
  1117. if (!wglMakeCurrent(mhDC, mhRC))
  1118. {
  1119. close();
  1120. OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1121. return FALSE;
  1122. }
  1123. if (!gGLManager.initGL())
  1124. {
  1125. close();
  1126. OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
  1127. return FALSE;
  1128. }
  1129. // Disable vertical sync for swap
  1130. if (disable_vsync && wglSwapIntervalEXT)
  1131. {
  1132. LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
  1133. wglSwapIntervalEXT(0);
  1134. }
  1135. else
  1136. {
  1137. LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
  1138. }
  1139. SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
  1140. // register this window as handling drag/drop events from the OS
  1141. DragAcceptFiles( mWindowHandle, TRUE );
  1142. mDragDrop->init( mWindowHandle );
  1143. //register joystick timer callback
  1144. SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer
  1145. // ok to post quit messages now
  1146. mPostQuit = TRUE;
  1147. if (auto_show)
  1148. {
  1149. show();
  1150. glClearColor(0.0f, 0.0f, 0.0f, 0.f);
  1151. glClear(GL_COLOR_BUFFER_BIT);
  1152. swapBuffers();
  1153. }
  1154. return TRUE;
  1155. }
  1156. void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
  1157. {
  1158. if( mIsMouseClipping )
  1159. {
  1160. RECT client_rect_in_screen_space;
  1161. if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
  1162. {
  1163. ClipCursor( &client_rect_in_screen_space );
  1164. }
  1165. }
  1166. // if the window was already maximized, MoveWindow seems to still set the maximized flag even if
  1167. // the window is smaller than maximized.
  1168. // So we're going to do a restore first (which is a ShowWindow call) (SL-44655).
  1169. // THIS CAUSES DEV-15484 and DEV-15949 
  1170. //ShowWindow(mWindowHandle, SW_RESTORE);
  1171. // NOW we can call MoveWindow
  1172. MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
  1173. }
  1174. BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
  1175. {
  1176. LLCoordScreen screen_pos;
  1177. mMousePositionModified = TRUE;
  1178. if (!mWindowHandle)
  1179. {
  1180. return FALSE;
  1181. }
  1182. if (!convertCoords(position, &screen_pos))
  1183. {
  1184. return FALSE;
  1185. }
  1186. // Inform the application of the new mouse position (needed for per-frame
  1187. // hover/picking to function).
  1188. LLCoordGL gl_pos;
  1189. convertCoords(position, &gl_pos);
  1190. mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
  1191. // DEV-18951 VWR-8524 Camera moves wildly when alt-clicking.
  1192. // Because we have preemptively notified the application of the new
  1193. // mouse position via handleMouseMove() above, we need to clear out
  1194. // any stale mouse move events.  RN/JC
  1195. MSG msg;
  1196. while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
  1197. { }
  1198. return SetCursorPos(screen_pos.mX, screen_pos.mY);
  1199. }
  1200. BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
  1201. {
  1202. POINT cursor_point;
  1203. LLCoordScreen screen_pos;
  1204. if (!mWindowHandle ||
  1205. !GetCursorPos(&cursor_point))
  1206. {
  1207. return FALSE;
  1208. }
  1209. screen_pos.mX = cursor_point.x;
  1210. screen_pos.mY = cursor_point.y;
  1211. return convertCoords(screen_pos, position);
  1212. }
  1213. void LLWindowWin32::hideCursor()
  1214. {
  1215. while (ShowCursor(FALSE) >= 0)
  1216. {
  1217. // nothing, wait for cursor to push down
  1218. }
  1219. mCursorHidden = TRUE;
  1220. mHideCursorPermanent = TRUE;
  1221. }
  1222. void LLWindowWin32::showCursor()
  1223. {
  1224. // makes sure the cursor shows up
  1225. while (ShowCursor(TRUE) < 0)
  1226. {
  1227. // do nothing, wait for cursor to pop out
  1228. }
  1229. mCursorHidden = FALSE;
  1230. mHideCursorPermanent = FALSE;
  1231. }
  1232. void LLWindowWin32::showCursorFromMouseMove()
  1233. {
  1234. if (!mHideCursorPermanent)
  1235. {
  1236. showCursor();
  1237. }
  1238. }
  1239. void LLWindowWin32::hideCursorUntilMouseMove()
  1240. {
  1241. if (!mHideCursorPermanent)
  1242. {
  1243. hideCursor();
  1244. mHideCursorPermanent = FALSE;
  1245. }
  1246. }
  1247. BOOL LLWindowWin32::isCursorHidden()
  1248. {
  1249. return mCursorHidden;
  1250. }
  1251. HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name)
  1252. {
  1253. return (HCURSOR)LoadImage(mhInstance,
  1254.   name,
  1255.   IMAGE_CURSOR,
  1256.   0, // default width
  1257.   0, // default height
  1258.   LR_DEFAULTCOLOR);
  1259. }
  1260. void LLWindowWin32::initCursors()
  1261. {
  1262. mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW);
  1263. mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT);
  1264. mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND);
  1265. mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM);
  1266. mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS);
  1267. mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE);
  1268. mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW);
  1269. mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE);  
  1270. mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS);  
  1271. mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO);
  1272. mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); 
  1273. HMODULE module = GetModuleHandle(NULL);
  1274. mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB"));
  1275. mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND"));
  1276. mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS"));
  1277. mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE"));
  1278. mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG"));
  1279. mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY"));
  1280. mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI"));
  1281. mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI"));
  1282. mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED"));
  1283. mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED"));
  1284. mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED"));
  1285. mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE"));
  1286. mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); 
  1287. mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE"));
  1288. mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA"));
  1289. mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN"));
  1290. mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
  1291. mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
  1292. mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
  1293. // Color cursors
  1294. mCursor[UI_CURSOR_TOOLPLAY] = loadColorCursor(TEXT("TOOLPLAY"));
  1295. mCursor[UI_CURSOR_TOOLPAUSE] = loadColorCursor(TEXT("TOOLPAUSE"));
  1296. mCursor[UI_CURSOR_TOOLMEDIAOPEN] = loadColorCursor(TEXT("TOOLMEDIAOPEN"));
  1297. // Note: custom cursors that are not found make LoadCursor() return NULL.
  1298. for( S32 i = 0; i < UI_CURSOR_COUNT; i++ )
  1299. {
  1300. if( !mCursor[i] )
  1301. {
  1302. mCursor[i] = LoadCursor(NULL, IDC_ARROW);
  1303. }
  1304. }
  1305. }
  1306. void LLWindowWin32::setCursor(ECursorType cursor)
  1307. {
  1308. if (cursor == UI_CURSOR_ARROW
  1309. && mBusyCount > 0)
  1310. {
  1311. cursor = UI_CURSOR_WORKING;
  1312. }
  1313. if( mCurrentCursor != cursor )
  1314. {
  1315. mCurrentCursor = cursor;
  1316. SetCursor( mCursor[cursor] );
  1317. }
  1318. }
  1319. ECursorType LLWindowWin32::getCursor() const
  1320. {
  1321. return mCurrentCursor;
  1322. }
  1323. void LLWindowWin32::captureMouse()
  1324. {
  1325. SetCapture(mWindowHandle);
  1326. }
  1327. void LLWindowWin32::releaseMouse()
  1328. {
  1329. // *NOTE:Mani ReleaseCapture will spawn new windows messages...
  1330. // which will in turn call our MainWindowProc. It therefore requires
  1331. // pausing *and more importantly resumption* of the mainlooptimeout...
  1332. // just like DispatchMessage below.
  1333. mCallbacks->handlePauseWatchdog(this);
  1334. ReleaseCapture();
  1335. mCallbacks->handleResumeWatchdog(this);
  1336. }
  1337. void LLWindowWin32::delayInputProcessing()
  1338. {
  1339. mInputProcessingPaused = TRUE;
  1340. }
  1341. void LLWindowWin32::gatherInput()
  1342. {
  1343. MSG msg;
  1344. int msg_count = 0;
  1345. LLMemType m1(LLMemType::MTYPE_GATHER_INPUT);
  1346. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE)
  1347. {
  1348. mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
  1349. TranslateMessage(&msg);
  1350. // turn watchdog off in here to not fail if windows is doing something wacky
  1351. mCallbacks->handlePauseWatchdog(this);
  1352. DispatchMessage(&msg);
  1353. mCallbacks->handleResumeWatchdog(this);
  1354. msg_count++;
  1355. if ( mInputProcessingPaused )
  1356. {
  1357. break;
  1358. }
  1359. /* Attempted workaround for problem where typing fast and hitting
  1360.    return would result in only part of the text being sent. JC
  1361. BOOL key_posted = TranslateMessage(&msg);
  1362. DispatchMessage(&msg);
  1363. msg_count++;
  1364. // If a key was translated, a WM_CHAR might have been posted to the end
  1365. // of the event queue.  We need it immediately.
  1366. if (key_posted && msg.message == WM_KEYDOWN)
  1367. {
  1368. if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
  1369. {
  1370. TranslateMessage(&msg);
  1371. DispatchMessage(&msg);
  1372. msg_count++;
  1373. }
  1374. }
  1375. */
  1376. mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput");
  1377. // For async host by name support.  Really hacky.
  1378. if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
  1379. {
  1380. gAsyncMsgCallback(msg);
  1381. }
  1382. }
  1383. mInputProcessingPaused = FALSE;
  1384. // clear this once we've processed all mouse messages that might have occurred after
  1385. // we slammed the mouse position
  1386. mMousePositionModified = FALSE;
  1387. }
  1388. static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard");
  1389. static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse");
  1390. LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
  1391. {
  1392. LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
  1393. if (NULL != window_imp)
  1394. {
  1395. window_imp->mCallbacks->handleResumeWatchdog(window_imp);
  1396. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc");
  1397. // Has user provided their own window callback?
  1398. if (NULL != window_imp->mWndProc)
  1399. {
  1400. if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
  1401. {
  1402. // user has handled window message
  1403. return 0;
  1404. }
  1405. }
  1406. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc");
  1407. // Juggle to make sure we can get negative positions for when
  1408. // mouse is outside window.
  1409. LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
  1410. // This doesn't work, as LOWORD returns unsigned short.
  1411. //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
  1412. LLCoordGL gl_coord;
  1413. // pass along extended flag in mask
  1414. MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
  1415. BOOL eat_keystroke = TRUE;
  1416. switch(u_msg)
  1417. {
  1418. RECT update_rect;
  1419. S32 update_width;
  1420. S32 update_height;
  1421. case WM_TIMER:
  1422. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER");
  1423. window_imp->mCallbacks->handleTimerEvent(window_imp);
  1424. break;
  1425. case WM_DEVICECHANGE:
  1426. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE");
  1427. if (gDebugWindowProc)
  1428. {
  1429. llinfos << "  WM_DEVICECHANGE: wParam=" << w_param 
  1430. << "; lParam=" << l_param << llendl;
  1431. }
  1432. if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
  1433. {
  1434. if (window_imp->mCallbacks->handleDeviceChange(window_imp))
  1435. {
  1436. return 0;
  1437. }
  1438. }
  1439. break;
  1440. case WM_PAINT:
  1441. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT");
  1442. GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
  1443. update_width = update_rect.right - update_rect.left + 1;
  1444. update_height = update_rect.bottom - update_rect.top + 1;
  1445. window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
  1446. update_width, update_height);
  1447. break;
  1448. case WM_PARENTNOTIFY:
  1449. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY");
  1450. u_msg = u_msg;
  1451. break;
  1452. case WM_SETCURSOR:
  1453. // This message is sent whenever the cursor is moved in a window.
  1454. // You need to set the appropriate cursor appearance.
  1455. // Only take control of cursor over client region of window
  1456. // This allows Windows(tm) to handle resize cursors, etc.
  1457. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR");
  1458. if (LOWORD(l_param) == HTCLIENT)
  1459. {
  1460. SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] );
  1461. return 0;
  1462. }
  1463. break;
  1464. case WM_ENTERMENULOOP:
  1465. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP");
  1466. window_imp->mCallbacks->handleWindowBlock(window_imp);
  1467. break;
  1468. case WM_EXITMENULOOP:
  1469. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP");
  1470. window_imp->mCallbacks->handleWindowUnblock(window_imp);
  1471. break;
  1472. case WM_ACTIVATEAPP:
  1473. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP");
  1474. {
  1475. // This message should be sent whenever the app gains or loses focus.
  1476. BOOL activating = (BOOL) w_param;
  1477. BOOL minimized = window_imp->getMinimized();
  1478. if (gDebugWindowProc)
  1479. {
  1480. LL_INFOS("Window") << "WINDOWPROC ActivateApp "
  1481. << " activating " << S32(activating)
  1482. << " minimized " << S32(minimized)
  1483. << " fullscreen " << S32(window_imp->mFullscreen)
  1484. << LL_ENDL;
  1485. }
  1486. if (window_imp->mFullscreen)
  1487. {
  1488. // When we run fullscreen, restoring or minimizing the app needs 
  1489. // to switch the screen resolution
  1490. if (activating)
  1491. {
  1492. window_imp->setFullscreenResolution();
  1493. window_imp->restore();
  1494. }
  1495. else
  1496. {
  1497. window_imp->minimize();
  1498. window_imp->resetDisplayResolution();
  1499. }
  1500. }
  1501. window_imp->mCallbacks->handleActivateApp(window_imp, activating);
  1502. break;
  1503. }
  1504. case WM_ACTIVATE:
  1505. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE");
  1506. {
  1507. // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
  1508. BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
  1509. BOOL minimized = BOOL(HIWORD(w_param));
  1510. if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
  1511. {
  1512. window_imp->interruptLanguageTextInput();
  1513. }
  1514. // JC - I'm not sure why, but if we don't report that we handled the 
  1515. // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
  1516. // properly when we run fullscreen.
  1517. if (gDebugWindowProc)
  1518. {
  1519. LL_INFOS("Window") << "WINDOWPROC Activate "
  1520. << " activating " << S32(activating) 
  1521. << " minimized " << S32(minimized)
  1522. << LL_ENDL;
  1523. }
  1524. // Don't handle this.
  1525. break;
  1526. }
  1527. case WM_QUERYOPEN:
  1528. // TODO: use this to return a nice icon
  1529. break;
  1530. case WM_SYSCOMMAND:
  1531. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND");
  1532. switch(w_param)
  1533. {
  1534. case SC_KEYMENU: 
  1535. // Disallow the ALT key from triggering the default system menu.
  1536. return 0;
  1537. case SC_SCREENSAVE:
  1538. case SC_MONITORPOWER:
  1539. // eat screen save messages and prevent them!
  1540. return 0;
  1541. }
  1542. break;
  1543. case WM_CLOSE:
  1544. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE");
  1545. // Will the app allow the window to close?
  1546. if (window_imp->mCallbacks->handleCloseRequest(window_imp))
  1547. {
  1548. // Get the app to initiate cleanup.
  1549. window_imp->mCallbacks->handleQuit(window_imp);
  1550. // The app is responsible for calling destroyWindow when done with GL
  1551. }
  1552. return 0;
  1553. case WM_DESTROY:
  1554. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY");
  1555. if (window_imp->shouldPostQuit())
  1556. {
  1557. PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
  1558. }
  1559. return 0;
  1560. case WM_COMMAND:
  1561. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND");
  1562. if (!HIWORD(w_param)) // this message is from a menu
  1563. {
  1564. window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param));
  1565. }
  1566. break;
  1567. case WM_SYSKEYDOWN:
  1568. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN");
  1569. // allow system keys, such as ALT-F4 to be processed by Windows
  1570. eat_keystroke = FALSE;
  1571. case WM_KEYDOWN:
  1572. window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next
  1573. window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
  1574. window_imp->mKeyVirtualKey = w_param;
  1575. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
  1576. {
  1577. if (gDebugWindowProc)
  1578. {
  1579. LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
  1580. << " key " << S32(w_param) 
  1581. << LL_ENDL;
  1582. }
  1583. if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke)
  1584. {
  1585. return 0;
  1586. }
  1587. // pass on to windows if we didn't handle it
  1588. break;
  1589. }
  1590. case WM_SYSKEYUP:
  1591. eat_keystroke = FALSE;
  1592. case WM_KEYUP:
  1593. {
  1594. window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff;
  1595. window_imp->mKeyVirtualKey = w_param;
  1596. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
  1597. LLFastTimer t2(FTM_KEYHANDLER);
  1598. if (gDebugWindowProc)
  1599. {
  1600. LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
  1601. << " key " << S32(w_param) 
  1602. << LL_ENDL;
  1603. }
  1604. if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke)
  1605. {
  1606. return 0;
  1607. }
  1608. // pass on to windows
  1609. break;
  1610. }
  1611. case WM_IME_SETCONTEXT:
  1612. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT");
  1613. if (gDebugWindowProc)
  1614. {
  1615. llinfos << "WM_IME_SETCONTEXT" << llendl;
  1616. }
  1617. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1618. {
  1619. l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
  1620. // Invoke DefWinProc with the modified LPARAM.
  1621. }
  1622. break;
  1623. case WM_IME_STARTCOMPOSITION:
  1624. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION");
  1625. if (gDebugWindowProc)
  1626. {
  1627. llinfos << "WM_IME_STARTCOMPOSITION" << llendl;
  1628. }
  1629. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1630. {
  1631. window_imp->handleStartCompositionMessage();
  1632. return 0;
  1633. }
  1634. break;
  1635. case WM_IME_ENDCOMPOSITION:
  1636. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION");
  1637. if (gDebugWindowProc)
  1638. {
  1639. llinfos << "WM_IME_ENDCOMPOSITION" << llendl;
  1640. }
  1641. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1642. {
  1643. return 0;
  1644. }
  1645. break;
  1646. case WM_IME_COMPOSITION:
  1647. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION");
  1648. if (gDebugWindowProc)
  1649. {
  1650. llinfos << "WM_IME_COMPOSITION" << llendl;
  1651. }
  1652. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1653. {
  1654. window_imp->handleCompositionMessage(l_param);
  1655. return 0;
  1656. }
  1657. break;
  1658. case WM_IME_REQUEST:
  1659. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
  1660. if (gDebugWindowProc)
  1661. {
  1662. llinfos << "WM_IME_REQUEST" << llendl;
  1663. }
  1664. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1665. {
  1666. LRESULT result = 0;
  1667. if (window_imp->handleImeRequests(w_param, l_param, &result))
  1668. {
  1669. return result;
  1670. }
  1671. }
  1672. break;
  1673. case WM_CHAR:
  1674. window_imp->mKeyCharCode = w_param;
  1675. // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
  1676. // to figure out how that works. - Doug
  1677. //
  1678. // ... Well, I don't think so.
  1679. // How it works is explained in Win32 API document, but WM_UNICHAR didn't work
  1680. // as specified at least on Windows XP SP1 Japanese version.  I have never used
  1681. // it since then, and I'm not sure whether it has been fixed now, but I don't think
  1682. // it is worth trying.  The good old WM_CHAR works just fine even for supplementary
  1683. // characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
  1684. // by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
  1685. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
  1686. if (gDebugWindowProc)
  1687. {
  1688. LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
  1689. << " key " << S32(w_param) 
  1690. << LL_ENDL;
  1691. }
  1692. // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
  1693. // we *did* processed the event, so I believe we should not pass it to DefWindowProc...
  1694. window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
  1695. return 0;
  1696. case WM_LBUTTONDOWN:
  1697. {
  1698. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
  1699. LLFastTimer t2(FTM_MOUSEHANDLER);
  1700. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1701. {
  1702. window_imp->interruptLanguageTextInput();
  1703. }
  1704. // Because we move the cursor position in the app, we need to query
  1705. // to find out where the cursor at the time the event is handled.
  1706. // If we don't do this, many clicks could get buffered up, and if the
  1707. // first click changes the cursor position, all subsequent clicks
  1708. // will occur at the wrong location.  JC
  1709. LLCoordWindow cursor_coord_window;
  1710. if (window_imp->mMousePositionModified)
  1711. {
  1712. window_imp->getCursorPosition(&cursor_coord_window);
  1713. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1714. }
  1715. else
  1716. {
  1717. window_imp->convertCoords(window_coord, &gl_coord);
  1718. }
  1719. MASK mask = gKeyboard->currentMask(TRUE);
  1720. // generate move event to update mouse coordinates
  1721. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1722. if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
  1723. {
  1724. return 0;
  1725. }
  1726. }
  1727. break;
  1728. case WM_LBUTTONDBLCLK:
  1729. //RN: ignore right button double clicks for now
  1730. //case WM_RBUTTONDBLCLK:
  1731. {
  1732. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK");
  1733. // Because we move the cursor position in the app, we need to query
  1734. // to find out where the cursor at the time the event is handled.
  1735. // If we don't do this, many clicks could get buffered up, and if the
  1736. // first click changes the cursor position, all subsequent clicks
  1737. // will occur at the wrong location.  JC
  1738. LLCoordWindow cursor_coord_window;
  1739. if (window_imp->mMousePositionModified)
  1740. {
  1741. window_imp->getCursorPosition(&cursor_coord_window);
  1742. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1743. }
  1744. else
  1745. {
  1746. window_imp->convertCoords(window_coord, &gl_coord);
  1747. }
  1748. MASK mask = gKeyboard->currentMask(TRUE);
  1749. // generate move event to update mouse coordinates
  1750. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1751. if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) )
  1752. {
  1753. return 0;
  1754. }
  1755. }
  1756. break;
  1757. case WM_LBUTTONUP:
  1758. {
  1759. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
  1760. LLFastTimer t2(FTM_MOUSEHANDLER);
  1761. //if (gDebugClicks)
  1762. //{
  1763. // LL_INFOS("Window") << "WndProc left button up" << LL_ENDL;
  1764. //}
  1765. // Because we move the cursor position in the app, we need to query
  1766. // to find out where the cursor at the time the event is handled.
  1767. // If we don't do this, many clicks could get buffered up, and if the
  1768. // first click changes the cursor position, all subsequent clicks
  1769. // will occur at the wrong location.  JC
  1770. LLCoordWindow cursor_coord_window;
  1771. if (window_imp->mMousePositionModified)
  1772. {
  1773. window_imp->getCursorPosition(&cursor_coord_window);
  1774. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1775. }
  1776. else
  1777. {
  1778. window_imp->convertCoords(window_coord, &gl_coord);
  1779. }
  1780. MASK mask = gKeyboard->currentMask(TRUE);
  1781. // generate move event to update mouse coordinates
  1782. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1783. if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask))
  1784. {
  1785. return 0;
  1786. }
  1787. }
  1788. break;
  1789. case WM_RBUTTONDBLCLK:
  1790. case WM_RBUTTONDOWN:
  1791. {
  1792. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN");
  1793. LLFastTimer t2(FTM_MOUSEHANDLER);
  1794. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1795. {
  1796. window_imp->interruptLanguageTextInput();
  1797. }
  1798. // Because we move the cursor position in the llviewerapp, we need to query
  1799. // to find out where the cursor at the time the event is handled.
  1800. // If we don't do this, many clicks could get buffered up, and if the
  1801. // first click changes the cursor position, all subsequent clicks
  1802. // will occur at the wrong location.  JC
  1803. LLCoordWindow cursor_coord_window;
  1804. if (window_imp->mMousePositionModified)
  1805. {
  1806. window_imp->getCursorPosition(&cursor_coord_window);
  1807. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1808. }
  1809. else
  1810. {
  1811. window_imp->convertCoords(window_coord, &gl_coord);
  1812. }
  1813. MASK mask = gKeyboard->currentMask(TRUE);
  1814. // generate move event to update mouse coordinates
  1815. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1816. if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask))
  1817. {
  1818. return 0;
  1819. }
  1820. }
  1821. break;
  1822. case WM_RBUTTONUP:
  1823. {
  1824. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP");
  1825. LLFastTimer t2(FTM_MOUSEHANDLER);
  1826. // Because we move the cursor position in the app, we need to query
  1827. // to find out where the cursor at the time the event is handled.
  1828. // If we don't do this, many clicks could get buffered up, and if the
  1829. // first click changes the cursor position, all subsequent clicks
  1830. // will occur at the wrong location.  JC
  1831. LLCoordWindow cursor_coord_window;
  1832. if (window_imp->mMousePositionModified)
  1833. {
  1834. window_imp->getCursorPosition(&cursor_coord_window);
  1835. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1836. }
  1837. else
  1838. {
  1839. window_imp->convertCoords(window_coord, &gl_coord);
  1840. }
  1841. MASK mask = gKeyboard->currentMask(TRUE);
  1842. // generate move event to update mouse coordinates
  1843. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1844. if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask))
  1845. {
  1846. return 0;
  1847. }
  1848. }
  1849. break;
  1850. case WM_MBUTTONDOWN:
  1851. // case WM_MBUTTONDBLCLK:
  1852. {
  1853. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN");
  1854. LLFastTimer t2(FTM_MOUSEHANDLER);
  1855. if (LLWinImm::isAvailable() && window_imp->mPreeditor)
  1856. {
  1857. window_imp->interruptLanguageTextInput();
  1858. }
  1859. // Because we move the cursor position in tllviewerhe app, we need to query
  1860. // to find out where the cursor at the time the event is handled.
  1861. // If we don't do this, many clicks could get buffered up, and if the
  1862. // first click changes the cursor position, all subsequent clicks
  1863. // will occur at the wrong location.  JC
  1864. LLCoordWindow cursor_coord_window;
  1865. if (window_imp->mMousePositionModified)
  1866. {
  1867. window_imp->getCursorPosition(&cursor_coord_window);
  1868. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1869. }
  1870. else
  1871. {
  1872. window_imp->convertCoords(window_coord, &gl_coord);
  1873. }
  1874. MASK mask = gKeyboard->currentMask(TRUE);
  1875. // generate move event to update mouse coordinates
  1876. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1877. if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask))
  1878. {
  1879. return 0;
  1880. }
  1881. }
  1882. break;
  1883. case WM_MBUTTONUP:
  1884. {
  1885. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP");
  1886. LLFastTimer t2(FTM_MOUSEHANDLER);
  1887. // Because we move the cursor position in the llviewer app, we need to query
  1888. // to find out where the cursor at the time the event is handled.
  1889. // If we don't do this, many clicks could get buffered up, and if the
  1890. // first click changes the cursor position, all subsequent clicks
  1891. // will occur at the wrong location.  JC
  1892. LLCoordWindow cursor_coord_window;
  1893. if (window_imp->mMousePositionModified)
  1894. {
  1895. window_imp->getCursorPosition(&cursor_coord_window);
  1896. window_imp->convertCoords(cursor_coord_window, &gl_coord);
  1897. }
  1898. else
  1899. {
  1900. window_imp->convertCoords(window_coord, &gl_coord);
  1901. }
  1902. MASK mask = gKeyboard->currentMask(TRUE);
  1903. // generate move event to update mouse coordinates
  1904. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1905. if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask))
  1906. {
  1907. return 0;
  1908. }
  1909. }
  1910. break;
  1911. case WM_MOUSEWHEEL:
  1912. {
  1913. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL");
  1914. static short z_delta = 0;
  1915. RECT client_rect;
  1916. // eat scroll events that occur outside our window, since we use mouse position to direct scroll
  1917. // instead of keyboard focus
  1918. // NOTE: mouse_coord is in *window* coordinates for scroll events
  1919. POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)};
  1920. if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord)
  1921. && GetClientRect(window_imp->mWindowHandle, &client_rect))
  1922. {
  1923. // we have a valid mouse point and client rect
  1924. if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x
  1925. || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y)
  1926. {
  1927. // mouse is outside of client rect, so don't do anything
  1928. return 0;
  1929. }
  1930. }
  1931. S16 incoming_z_delta = HIWORD(w_param);
  1932. z_delta += incoming_z_delta;
  1933. // cout << "z_delta " << z_delta << endl;
  1934. // current mouse wheels report changes in increments of zDelta (+120, -120)
  1935. // Future, higher resolution mouse wheels may report smaller deltas.
  1936. // So we sum the deltas and only act when we've exceeded WHEEL_DELTA
  1937. //
  1938. // If the user rapidly spins the wheel, we can get messages with
  1939. // large deltas, like 480 or so.  Thus we need to scroll more quickly.
  1940. if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
  1941. {
  1942. window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA);
  1943. z_delta = 0;
  1944. }
  1945. return 0;
  1946. }
  1947. /*
  1948. // TODO: add this after resolving _WIN32_WINNT issue
  1949. case WM_MOUSELEAVE:
  1950. {
  1951. window_imp->mCallbacks->handleMouseLeave(window_imp);
  1952. // TRACKMOUSEEVENT track_mouse_event;
  1953. // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
  1954. // track_mouse_event.dwFlags = TME_LEAVE;
  1955. // track_mouse_event.hwndTrack = h_wnd;
  1956. // track_mouse_event.dwHoverTime = HOVER_DEFAULT;
  1957. // TrackMouseEvent( &track_mouse_event ); 
  1958. return 0;
  1959. }
  1960. */
  1961. // Handle mouse movement within the window
  1962. case WM_MOUSEMOVE:
  1963. {
  1964. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE");
  1965. window_imp->convertCoords(window_coord, &gl_coord);
  1966. MASK mask = gKeyboard->currentMask(TRUE);
  1967. window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
  1968. return 0;
  1969. }
  1970. case WM_SIZE:
  1971. {
  1972. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE");
  1973. S32 width = S32( LOWORD(l_param) );
  1974. S32 height = S32( HIWORD(l_param) );
  1975. if (gDebugWindowProc)
  1976. {
  1977. BOOL maximized = ( w_param == SIZE_MAXIMIZED );
  1978. BOOL restored  = ( w_param == SIZE_RESTORED );
  1979. BOOL minimized = ( w_param == SIZE_MINIMIZED );
  1980. LL_INFOS("Window") << "WINDOWPROC Size "
  1981. << width << "x" << height
  1982. << " max " << S32(maximized)
  1983. << " min " << S32(minimized)
  1984. << " rest " << S32(restored)
  1985. << LL_ENDL;
  1986. }
  1987. // There's an odd behavior with WM_SIZE that I would call a bug. If 
  1988. // the window is maximized, and you call MoveWindow() with a size smaller
  1989. // than a maximized window, it ends up sending WM_SIZE with w_param set 
  1990. // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work.
  1991. // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see 
  1992. // LLWindowWin32::moveWindow in this file). 
  1993. // If we are now restored, but we weren't before, this
  1994. // means that the window was un-minimized.
  1995. if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
  1996. {
  1997. window_imp->mCallbacks->handleActivate(window_imp, TRUE);
  1998. }
  1999. // handle case of window being maximized from fully minimized state
  2000. if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
  2001. {
  2002. window_imp->mCallbacks->handleActivate(window_imp, TRUE);
  2003. }
  2004. // Also handle the minimization case
  2005. if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
  2006. {
  2007. window_imp->mCallbacks->handleActivate(window_imp, FALSE);
  2008. }
  2009. // Actually resize all of our views
  2010. if (w_param != SIZE_MINIMIZED)
  2011. {
  2012. // Ignore updates for minimizing and minimized "windows"
  2013. window_imp->mCallbacks->handleResize( window_imp, 
  2014. LOWORD(l_param), 
  2015. HIWORD(l_param) );
  2016. }
  2017. window_imp->mLastSizeWParam = w_param;
  2018. return 0;
  2019. }
  2020. case WM_SETFOCUS:
  2021. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS");
  2022. if (gDebugWindowProc)
  2023. {
  2024. LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
  2025. }
  2026. window_imp->mCallbacks->handleFocus(window_imp);
  2027. return 0;
  2028. case WM_KILLFOCUS:
  2029. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS");
  2030. if (gDebugWindowProc)
  2031. {
  2032. LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
  2033. }
  2034. window_imp->mCallbacks->handleFocusLost(window_imp);
  2035. return 0;
  2036. case WM_COPYDATA:
  2037. {
  2038. window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA");
  2039. // received a URL
  2040. PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param;
  2041. window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData);
  2042. };
  2043. return 0;
  2044. break;
  2045. }
  2046. window_imp->mCallbacks->handlePauseWatchdog(window_imp);
  2047. }
  2048. // pass unhandled messages down to Windows
  2049. return DefWindowProc(h_wnd, u_msg, w_param, l_param);
  2050. }
  2051. BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to)
  2052. {
  2053. S32 client_height;
  2054. RECT client_rect;
  2055. LLCoordWindow window_position;
  2056. if (!mWindowHandle ||
  2057. !GetClientRect(mWindowHandle, &client_rect) ||
  2058. NULL == to)
  2059. {
  2060. return FALSE;
  2061. }
  2062. to->mX = from.mX;
  2063. client_height = client_rect.bottom - client_rect.top;
  2064. to->mY = client_height - from.mY - 1;
  2065. return TRUE;
  2066. }
  2067. BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to)
  2068. {
  2069. S32 client_height;
  2070. RECT client_rect;
  2071. if (!mWindowHandle ||
  2072. !GetClientRect(mWindowHandle, &client_rect) ||
  2073. NULL == to)
  2074. {
  2075. return FALSE;
  2076. }
  2077. to->mX = from.mX;
  2078. client_height = client_rect.bottom - client_rect.top;
  2079. to->mY = client_height - from.mY - 1;
  2080. return TRUE;
  2081. }
  2082. BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to)
  2083. {
  2084. POINT mouse_point;
  2085. mouse_point.x = from.mX;
  2086. mouse_point.y = from.mY;
  2087. BOOL result = ScreenToClient(mWindowHandle, &mouse_point);
  2088. if (result)
  2089. {
  2090. to->mX = mouse_point.x;
  2091. to->mY = mouse_point.y;
  2092. }
  2093. return result;
  2094. }
  2095. BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to)
  2096. {
  2097. POINT mouse_point;
  2098. mouse_point.x = from.mX;
  2099. mouse_point.y = from.mY;
  2100. BOOL result = ClientToScreen(mWindowHandle, &mouse_point);
  2101. if (result)
  2102. {
  2103. to->mX = mouse_point.x;
  2104. to->mY = mouse_point.y;
  2105. }
  2106. return result;
  2107. }
  2108. BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to)
  2109. {
  2110. LLCoordWindow window_coord;
  2111. if (!mWindowHandle || (NULL == to))
  2112. {
  2113. return FALSE;
  2114. }
  2115. convertCoords(from, &window_coord);
  2116. convertCoords(window_coord, to);
  2117. return TRUE;
  2118. }
  2119. BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to)
  2120. {
  2121. LLCoordWindow window_coord;
  2122. if (!mWindowHandle || (NULL == to))
  2123. {
  2124. return FALSE;
  2125. }
  2126. convertCoords(from, &window_coord);
  2127. convertCoords(window_coord, to);
  2128. return TRUE;
  2129. }
  2130. BOOL LLWindowWin32::isClipboardTextAvailable()
  2131. {
  2132. return IsClipboardFormatAvailable(CF_UNICODETEXT);
  2133. }
  2134. BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst)
  2135. {
  2136. BOOL success = FALSE;
  2137. if (IsClipboardFormatAvailable(CF_UNICODETEXT))
  2138. {
  2139. if (OpenClipboard(mWindowHandle))
  2140. {
  2141. HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT);
  2142. if (h_data)
  2143. {
  2144. WCHAR *utf16str = (WCHAR*) GlobalLock(h_data);
  2145. if (utf16str)
  2146. {
  2147. dst = utf16str_to_wstring(utf16str);
  2148. LLWStringUtil::removeCRLF(dst);
  2149. GlobalUnlock(h_data);
  2150. success = TRUE;
  2151. }
  2152. }
  2153. CloseClipboard();
  2154. }
  2155. }
  2156. return success;
  2157. }
  2158. BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
  2159. {
  2160. BOOL success = FALSE;
  2161. if (OpenClipboard(mWindowHandle))
  2162. {
  2163. EmptyClipboard();
  2164. // Provide a copy of the data in Unicode format.
  2165. LLWString sanitized_string(wstr);
  2166. LLWStringUtil::addCRLF(sanitized_string);
  2167. llutf16string out_utf16 = wstring_to_utf16str(sanitized_string);
  2168. const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR);
  2169. // Memory is allocated and then ownership of it is transfered to the system.
  2170. HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); 
  2171. if (hglobal_copy_utf16)
  2172. {
  2173. WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16);
  2174. if (copy_utf16)
  2175. {
  2176. memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */
  2177. GlobalUnlock(hglobal_copy_utf16);
  2178. if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16))
  2179. {
  2180. success = TRUE;
  2181. }
  2182. }
  2183. }
  2184. CloseClipboard();
  2185. }
  2186. return success;
  2187. }
  2188. // Constrains the mouse to the window.
  2189. void LLWindowWin32::setMouseClipping( BOOL b )
  2190. {
  2191. if( b != mIsMouseClipping )
  2192. {
  2193. BOOL success = FALSE;
  2194. if( b )
  2195. {
  2196. GetClipCursor( &mOldMouseClip );
  2197. RECT client_rect_in_screen_space;
  2198. if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
  2199. {
  2200. success = ClipCursor( &client_rect_in_screen_space );
  2201. }
  2202. }
  2203. else
  2204. {
  2205. // Must restore the old mouse clip, which may be set by another window.
  2206. success = ClipCursor( &mOldMouseClip );
  2207. SetRect( &mOldMouseClip, 0, 0, 0, 0 );
  2208. }
  2209. if( success )
  2210. {
  2211. mIsMouseClipping = b;
  2212. }
  2213. }
  2214. }
  2215. BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
  2216. {
  2217. BOOL success = FALSE;
  2218. RECT client_rect;
  2219. if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) )
  2220. {
  2221. POINT top_left;
  2222. top_left.x = client_rect.left;
  2223. top_left.y = client_rect.top;
  2224. ClientToScreen(mWindowHandle, &top_left); 
  2225. POINT bottom_right;
  2226. bottom_right.x = client_rect.right;
  2227. bottom_right.y = client_rect.bottom;
  2228. ClientToScreen(mWindowHandle, &bottom_right); 
  2229. SetRect( rectp,
  2230. top_left.x,
  2231. top_left.y,
  2232. bottom_right.x,
  2233. bottom_right.y );
  2234. success = TRUE;
  2235. }
  2236. return success;
  2237. }
  2238. void LLWindowWin32::flashIcon(F32 seconds)
  2239. {
  2240. FLASHWINFO flash_info;
  2241. flash_info.cbSize = sizeof(FLASHWINFO);
  2242. flash_info.hwnd = mWindowHandle;
  2243. flash_info.dwFlags = FLASHW_TRAY;
  2244. flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
  2245. flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
  2246. FlashWindowEx(&flash_info);
  2247. }
  2248. F32 LLWindowWin32::getGamma()
  2249. {
  2250. return mCurrentGamma;
  2251. }
  2252. BOOL LLWindowWin32::restoreGamma()
  2253. {
  2254. return SetDeviceGammaRamp(mhDC, mPrevGammaRamp);
  2255. }
  2256. BOOL LLWindowWin32::setGamma(const F32 gamma)
  2257. {
  2258. mCurrentGamma = gamma;
  2259. LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL;
  2260. for ( int i = 0; i < 256; ++i )
  2261. {
  2262. int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f );
  2263. int value = mult * i;
  2264. if ( value > 0xffff )
  2265. value = 0xffff;
  2266. mCurrentGammaRamp [ 0 * 256 + i ] = 
  2267. mCurrentGammaRamp [ 1 * 256 + i ] = 
  2268. mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value;
  2269. };
  2270. return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp );
  2271. }
  2272. void LLWindowWin32::setFSAASamples(const U32 fsaa_samples)
  2273. {
  2274. mFSAASamples = fsaa_samples;
  2275. }
  2276. U32 LLWindowWin32::getFSAASamples()
  2277. {
  2278. return mFSAASamples;
  2279. }
  2280. LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
  2281. {
  2282. if (!mSupportedResolutions)
  2283. {
  2284. mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
  2285. DEVMODE dev_mode;
  2286. mNumSupportedResolutions = 0;
  2287. for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++)
  2288. {
  2289. if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
  2290. {
  2291. break;
  2292. }
  2293. if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL &&
  2294. dev_mode.dmPelsWidth >= 800 &&
  2295. dev_mode.dmPelsHeight >= 600)
  2296. {
  2297. BOOL resolution_exists = FALSE;
  2298. for(S32 i = 0; i < mNumSupportedResolutions; i++)
  2299. {
  2300. if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth &&
  2301. mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight)
  2302. {
  2303. resolution_exists = TRUE;
  2304. }
  2305. }
  2306. if (!resolution_exists)
  2307. {
  2308. mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth;
  2309. mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight;
  2310. mNumSupportedResolutions++;
  2311. }
  2312. }
  2313. }
  2314. }
  2315. num_resolutions = mNumSupportedResolutions;
  2316. return mSupportedResolutions;
  2317. }
  2318. F32 LLWindowWin32::getNativeAspectRatio()
  2319. {
  2320. if (mOverrideAspectRatio > 0.f)
  2321. {
  2322. return mOverrideAspectRatio;
  2323. }
  2324. else if (mNativeAspectRatio > 0.f)
  2325. {
  2326. // we grabbed this value at startup, based on the user's desktop settings
  2327. return mNativeAspectRatio;
  2328. }
  2329. // RN: this hack presumes that the largest supported resolution is monitor-limited
  2330. // and that pixels in that mode are square, therefore defining the native aspect ratio
  2331. // of the monitor...this seems to work to a close approximation for most CRTs/LCDs
  2332. S32 num_resolutions;
  2333. LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions);
  2334. return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight);
  2335. }
  2336. F32 LLWindowWin32::getPixelAspectRatio()
  2337. {
  2338. F32 pixel_aspect = 1.f;
  2339. if (getFullscreen())
  2340. {
  2341. LLCoordScreen screen_size;
  2342. getSize(&screen_size);
  2343. pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX;
  2344. }
  2345. return pixel_aspect;
  2346. }
  2347. // Change display resolution.  Returns true if successful.
  2348. // protected
  2349. BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
  2350. {
  2351. DEVMODE dev_mode;
  2352. dev_mode.dmSize = sizeof(dev_mode);
  2353. BOOL success = FALSE;
  2354. // Don't change anything if we don't have to
  2355. if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
  2356. {
  2357. if (dev_mode.dmPelsWidth        == width &&
  2358. dev_mode.dmPelsHeight       == height &&
  2359. dev_mode.dmBitsPerPel       == bits &&
  2360. dev_mode.dmDisplayFrequency == refresh )
  2361. {
  2362. // ...display mode identical, do nothing
  2363. return TRUE;
  2364. }
  2365. }
  2366. memset(&dev_mode, 0, sizeof(dev_mode));
  2367. dev_mode.dmSize = sizeof(dev_mode);
  2368. dev_mode.dmPelsWidth        = width;
  2369. dev_mode.dmPelsHeight       = height;
  2370. dev_mode.dmBitsPerPel       = bits;
  2371. dev_mode.dmDisplayFrequency = refresh;
  2372. dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
  2373. // CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
  2374. LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
  2375. success = (DISP_CHANGE_SUCCESSFUL == cds_result);
  2376. if (!success)
  2377. {
  2378. LL_WARNS("Window") << "setDisplayResolution failed, "
  2379. << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL;
  2380. }
  2381. return success;
  2382. }
  2383. // protected
  2384. BOOL LLWindowWin32::setFullscreenResolution()
  2385. {
  2386. if (mFullscreen)
  2387. {
  2388. return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
  2389. }
  2390. else
  2391. {
  2392. return FALSE;
  2393. }
  2394. }
  2395. // protected
  2396. BOOL LLWindowWin32::resetDisplayResolution()
  2397. {
  2398. LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL;
  2399. LONG cds_result = ChangeDisplaySettings(NULL, 0);
  2400. BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result);
  2401. if (!success)
  2402. {
  2403. LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL;
  2404. }
  2405. LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL;
  2406. return success;
  2407. }
  2408. void LLWindowWin32::swapBuffers()
  2409. {
  2410. SwapBuffers(mhDC);
  2411. }
  2412. //
  2413. // LLSplashScreenImp
  2414. //
  2415. LLSplashScreenWin32::LLSplashScreenWin32()
  2416. : mWindow(NULL)
  2417. {
  2418. }
  2419. LLSplashScreenWin32::~LLSplashScreenWin32()
  2420. {
  2421. }
  2422. void LLSplashScreenWin32::showImpl()
  2423. {
  2424. // This appears to work.  ???
  2425. HINSTANCE hinst = GetModuleHandle(NULL);
  2426. mWindow = CreateDialog(hinst, 
  2427. TEXT("SPLASHSCREEN"), 
  2428. NULL, // no parent
  2429. (DLGPROC) LLSplashScreenWin32::windowProc); 
  2430. ShowWindow(mWindow, SW_SHOW);
  2431. }
  2432. void LLSplashScreenWin32::updateImpl(const std::string& mesg)
  2433. {
  2434. if (!mWindow) return;
  2435. WCHAR w_mesg[1024];
  2436. mbstowcs(w_mesg, mesg.c_str(), 1024);
  2437. SendDlgItemMessage(mWindow,
  2438. 666, // HACK: text id
  2439. WM_SETTEXT,
  2440. FALSE,
  2441. (LPARAM)w_mesg);
  2442. }
  2443. void LLSplashScreenWin32::hideImpl()
  2444. {
  2445. if (mWindow)
  2446. {
  2447. DestroyWindow(mWindow);
  2448. mWindow = NULL; 
  2449. }
  2450. }
  2451. // static
  2452. LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg,
  2453. WPARAM w_param, LPARAM l_param)
  2454. {
  2455. // Just give it to windows
  2456. return DefWindowProc(h_wnd, u_msg, w_param, l_param);
  2457. }
  2458. //
  2459. // Helper Funcs
  2460. //
  2461. S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type)
  2462. {
  2463. UINT uType;
  2464. switch(type)
  2465. {
  2466. case OSMB_OK:
  2467. uType = MB_OK;
  2468. break;
  2469. case OSMB_OKCANCEL:
  2470. uType = MB_OKCANCEL;
  2471. break;
  2472. case OSMB_YESNO:
  2473. uType = MB_YESNO;
  2474. break;
  2475. default:
  2476. uType = MB_OK;
  2477. break;
  2478. }
  2479. // HACK! Doesn't properly handle wide strings!
  2480. int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType);
  2481. S32 retval;
  2482. switch(retval_win)
  2483. {
  2484. case IDYES:
  2485. retval = OSBTN_YES;
  2486. break;
  2487. case IDNO:
  2488. retval = OSBTN_NO;
  2489. break;
  2490. case IDOK:
  2491. retval = OSBTN_OK;
  2492. break;
  2493. case IDCANCEL:
  2494. retval = OSBTN_CANCEL;
  2495. break;
  2496. default:
  2497. retval = OSBTN_CANCEL;
  2498. break;
  2499. }
  2500. return retval;
  2501. }
  2502. void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url )
  2503. {
  2504. bool found = false;
  2505. S32 i;
  2506. for (i = 0; i < gURLProtocolWhitelistCount; i++)
  2507. {
  2508. if (escaped_url.find(gURLProtocolWhitelist[i]) == 0)
  2509. {
  2510. found = true;
  2511. break;
  2512. }
  2513. }
  2514. if (!found)
  2515. {
  2516. LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL;
  2517. return;
  2518. }
  2519. LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL;
  2520. // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work
  2521. // reliablly on Vista.
  2522. // this is madness.. no, this is..
  2523. LLWString url_wstring = utf8str_to_wstring( escaped_url );
  2524. llutf16string url_utf16 = wstring_to_utf16str( url_wstring );
  2525. // let the OS decide what to use to open the URL
  2526. SHELLEXECUTEINFO sei = { sizeof( sei ) };
  2527. sei.fMask = SEE_MASK_FLAG_DDEWAIT;
  2528. sei.nShow = SW_SHOWNORMAL;
  2529. sei.lpVerb = L"open";
  2530. sei.lpFile = url_utf16.c_str();
  2531. ShellExecuteEx( &sei );
  2532. //// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES
  2533. //// DELETE THIS ONCE THE MERGES ARE DONE
  2534. // Figure out the user's default web browser
  2535. // HKEY_CLASSES_ROOThttpshellopencommand
  2536. /*
  2537. std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\shell\open\command";
  2538. WCHAR reg_path_wstr[256];
  2539. mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) );
  2540. HKEY key;
  2541. WCHAR browser_open_wstr[1024];
  2542. DWORD buffer_length = 1024;
  2543. RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key);
  2544. RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length);
  2545. RegCloseKey(key);
  2546. // Convert to STL string
  2547. LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr);
  2548. if (browser_open_wstring.length() < 2)
  2549. {
  2550. LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL;
  2551. return;
  2552. }
  2553. // Extract the process that's supposed to be launched
  2554. LLWString browser_executable;
  2555. if (browser_open_wstring[0] == '"')
  2556. {
  2557. // executable is quoted, find the matching quote
  2558. size_t quote_pos = browser_open_wstring.find('"', 1);
  2559. // copy out the string including both quotes
  2560. browser_executable = browser_open_wstring.substr(0, quote_pos+1);
  2561. }
  2562. else
  2563. {
  2564. // executable not quoted, find a space
  2565. size_t space_pos = browser_open_wstring.find(' ', 1);
  2566. browser_executable = browser_open_wstring.substr(0, space_pos);
  2567. }
  2568. LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL;
  2569. LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL;
  2570. // Convert URL to wide string for Windows API
  2571. // Assume URL is UTF8, as can come from scripts
  2572. LLWString url_wstring = utf8str_to_wstring(escaped_url);
  2573. llutf16string url_utf16 = wstring_to_utf16str(url_wstring);
  2574. // Convert executable and path to wide string for Windows API
  2575. llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable);
  2576. // ShellExecute returns HINSTANCE for backwards compatiblity.
  2577. // MS docs say to cast to int and compare to 32.
  2578. HWND our_window = NULL;
  2579. LPCWSTR directory_wstr = NULL;
  2580. int retval = (int) ShellExecute(our_window,  // Flawfinder: ignore
  2581. L"open", 
  2582. browser_exec_utf16.c_str(), 
  2583. url_utf16.c_str(), 
  2584. directory_wstr,
  2585. SW_SHOWNORMAL);
  2586. if (retval > 32)
  2587. {
  2588. LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL;
  2589. }
  2590. else
  2591. {
  2592. LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL;
  2593. }
  2594. */
  2595. }
  2596. /*
  2597. Make the raw keyboard data available - used to poke through to LLQtWebKit so
  2598. that Qt/Webkit has access to the virtual keycodes etc. that it needs
  2599. */
  2600. LLSD LLWindowWin32::getNativeKeyData()
  2601. {
  2602. LLSD result = LLSD::emptyMap();
  2603. result["scan_code"] = (S32)mKeyScanCode;
  2604. result["virtual_key"] = (S32)mKeyVirtualKey;
  2605. return result;
  2606. }
  2607. BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b )
  2608. {
  2609. BOOL retval = FALSE;
  2610. static CHOOSECOLOR cc;
  2611. static COLORREF crCustColors[16];
  2612. cc.lStructSize = sizeof(CHOOSECOLOR);
  2613. cc.hwndOwner = mWindowHandle;
  2614. cc.hInstance = NULL;
  2615. cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f));
  2616. //cc.rgbResult = RGB (0x80,0x80,0x80); 
  2617. cc.lpCustColors = crCustColors;
  2618. cc.Flags = CC_RGBINIT | CC_FULLOPEN;
  2619. cc.lCustData = 0;
  2620. cc.lpfnHook = NULL;
  2621. cc.lpTemplateName = NULL;
  2622.  
  2623. // This call is modal, so pause agent
  2624. //send_agent_pause(); // this is in newview and we don't want to set up a dependency
  2625. {
  2626. retval = ChooseColor(&cc);
  2627. }
  2628. //send_agent_resume(); // this is in newview and we don't want to set up a dependency
  2629. *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f;
  2630. *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f;
  2631. *r = ((F32)(cc.rgbResult & 0xff)) / 255.f;
  2632. return (retval);
  2633. }
  2634. void *LLWindowWin32::getPlatformWindow()
  2635. {
  2636. return (void*)mWindowHandle;
  2637. }
  2638. void LLWindowWin32::bringToFront()
  2639. {
  2640. BringWindowToTop(mWindowHandle);
  2641. }
  2642. // set (OS) window focus back to the client
  2643. void LLWindowWin32::focusClient()
  2644. {
  2645. SetFocus ( mWindowHandle );
  2646. }
  2647. void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
  2648. {
  2649. if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable())
  2650. {
  2651. return;
  2652. }
  2653. if (preeditor != mPreeditor && !b)
  2654. {
  2655. // This condition may occur with a call to
  2656. // setEnabled(BOOL) from LLTextEditor or LLLineEditor
  2657. // when the control is not focused.
  2658. // We need to silently ignore the case so that
  2659. // the language input status of the focused control
  2660. // is not disturbed.
  2661. return;
  2662. }
  2663. // Take care of old and new preeditors.
  2664. if (preeditor != mPreeditor || !b)
  2665. {
  2666. if (sLanguageTextInputAllowed)
  2667. {
  2668. interruptLanguageTextInput();
  2669. }
  2670. mPreeditor = (b ? preeditor : NULL);
  2671. }
  2672. sLanguageTextInputAllowed = b;
  2673. if ( sLanguageTextInputAllowed )
  2674. {
  2675. // Allowing: Restore the previous IME status, so that the user has a feeling that the previous 
  2676. // text input continues naturally.  Be careful, however, the IME status is meaningful only during the user keeps 
  2677. // using same Input Locale (aka Keyboard Layout).
  2678. if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale)
  2679. {
  2680. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2681. LLWinImm::setOpenStatus(himc, TRUE);
  2682. LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode);
  2683. LLWinImm::releaseContext(mWindowHandle, himc);
  2684. }
  2685. }
  2686. else
  2687. {
  2688. // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly.
  2689. // However, do it after saving the current IME  status.  We need to restore the status when
  2690. //   allowing language text input again.
  2691. sWinInputLocale = GetKeyboardLayout(0);
  2692. sWinIMEOpened = LLWinImm::isIME(sWinInputLocale);
  2693. if (sWinIMEOpened)
  2694. {
  2695. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2696. sWinIMEOpened = LLWinImm::getOpenStatus(himc);
  2697. if (sWinIMEOpened)
  2698. {
  2699. LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode);
  2700. // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's 
  2701. // keyboard hooking, because Some IME reacts only on the former and some other on the latter...
  2702. LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode);
  2703. LLWinImm::setOpenStatus(himc, FALSE);
  2704. }
  2705. LLWinImm::releaseContext(mWindowHandle, himc);
  2706.   }
  2707. }
  2708. }
  2709. void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, 
  2710. CANDIDATEFORM *form)
  2711. {
  2712. LLCoordWindow caret_coord, top_left, bottom_right;
  2713. convertCoords(caret, &caret_coord);
  2714. convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
  2715. convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
  2716. memset(form, 0, sizeof(CANDIDATEFORM));
  2717. form->dwStyle = CFS_EXCLUDE;
  2718. form->ptCurrentPos.x = caret_coord.mX;
  2719. form->ptCurrentPos.y = caret_coord.mY;
  2720. form->rcArea.left   = top_left.mX;
  2721. form->rcArea.top    = top_left.mY;
  2722. form->rcArea.right  = bottom_right.mX;
  2723. form->rcArea.bottom = bottom_right.mY;
  2724. }
  2725. // Put the IME window at the right place (near current text input).   Point coordinates should be the top of the current text line.
  2726. void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
  2727. {
  2728. if (sLanguageTextInputAllowed && LLWinImm::isAvailable())
  2729. {
  2730. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2731. LLCoordWindow win_pos;
  2732. convertCoords( position, &win_pos );
  2733. if ( win_pos.mX >= 0 && win_pos.mY >= 0 && 
  2734. (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) )
  2735. {
  2736. COMPOSITIONFORM ime_form;
  2737. memset( &ime_form, 0, sizeof(ime_form) );
  2738. ime_form.dwStyle = CFS_POINT;
  2739. ime_form.ptCurrentPos.x = win_pos.mX;
  2740. ime_form.ptCurrentPos.y = win_pos.mY;
  2741. LLWinImm::setCompositionWindow( himc, &ime_form );
  2742. sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY );
  2743. }
  2744. LLWinImm::releaseContext(mWindowHandle, himc);
  2745. }
  2746. }
  2747. void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control,
  2748. IMECHARPOSITION *char_position)
  2749. {
  2750. LLCoordScreen caret_coord, top_left, bottom_right;
  2751. convertCoords(caret, &caret_coord);
  2752. convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
  2753. convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
  2754. char_position->pt.x = caret_coord.mX;
  2755. char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character...
  2756. char_position->cLineHeight = bottom_right.mY - top_left.mY;
  2757. char_position->rcDocument.left   = top_left.mX;
  2758. char_position->rcDocument.top    = top_left.mY;
  2759. char_position->rcDocument.right  = bottom_right.mX;
  2760. char_position->rcDocument.bottom = bottom_right.mY;
  2761. }
  2762. void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
  2763. {
  2764. // Our font is a list of FreeType recognized font files that may
  2765. // not have a corresponding ones in Windows' fonts.  Hence, we
  2766. // can't simply tell Windows which font we are using.  We will
  2767. // notify a _standard_ font for a current input locale instead.
  2768. // We use a hard-coded knowledge about the Windows' standard
  2769. // configuration to do so...
  2770. memset(logfont, 0, sizeof(LOGFONT));
  2771. const WORD lang_id = LOWORD(GetKeyboardLayout(0));
  2772. switch (PRIMARYLANGID(lang_id))
  2773. {
  2774. case LANG_CHINESE:
  2775. // We need to identify one of two Chinese fonts.
  2776. switch (SUBLANGID(lang_id))
  2777. {
  2778. case SUBLANG_CHINESE_SIMPLIFIED:
  2779. case SUBLANG_CHINESE_SINGAPORE:
  2780. logfont->lfCharSet = GB2312_CHARSET;
  2781. lstrcpy(logfont->lfFaceName, TEXT("SimHei"));
  2782. break;
  2783. case SUBLANG_CHINESE_TRADITIONAL:
  2784. case SUBLANG_CHINESE_HONGKONG:
  2785. case SUBLANG_CHINESE_MACAU:
  2786. default:
  2787. logfont->lfCharSet = CHINESEBIG5_CHARSET;
  2788. lstrcpy(logfont->lfFaceName, TEXT("MingLiU"));
  2789. break;
  2790. }
  2791. break;
  2792. case LANG_JAPANESE:
  2793. logfont->lfCharSet = SHIFTJIS_CHARSET;
  2794. lstrcpy(logfont->lfFaceName, TEXT("MS Gothic"));
  2795. break;
  2796. case LANG_KOREAN:
  2797. logfont->lfCharSet = HANGUL_CHARSET;
  2798. lstrcpy(logfont->lfFaceName, TEXT("Gulim"));
  2799. break;
  2800. default:
  2801. logfont->lfCharSet = ANSI_CHARSET;
  2802. lstrcpy(logfont->lfFaceName, TEXT("Tahoma"));
  2803. break;
  2804. }
  2805. logfont->lfHeight = mPreeditor->getPreeditFontSize();
  2806. logfont->lfWeight = FW_NORMAL;
  2807. }
  2808. U32 LLWindowWin32::fillReconvertString(const LLWString &text,
  2809. S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string)
  2810. {
  2811. const llutf16string text_utf16 = wstring_to_utf16str(text);
  2812. const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR);
  2813. if (reconvert_string && reconvert_string->dwSize >= required_size)
  2814. {
  2815. const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus);
  2816. const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length);
  2817. reconvert_string->dwVersion = 0;
  2818. reconvert_string->dwStrLen = text_utf16.length();
  2819. reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING);
  2820. reconvert_string->dwCompStrLen = focus_utf16_length;
  2821. reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR);
  2822. reconvert_string->dwTargetStrLen = 0;
  2823. reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR);
  2824. const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING));
  2825. memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR));
  2826. }
  2827. return required_size;
  2828. }
  2829. void LLWindowWin32::updateLanguageTextInputArea()
  2830. {
  2831. if (!mPreeditor || !LLWinImm::isAvailable())
  2832. {
  2833. return;
  2834. }
  2835. LLCoordGL caret_coord;
  2836. LLRect preedit_bounds;
  2837. if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL))
  2838. {
  2839. mLanguageTextInputPointGL = caret_coord;
  2840. mLanguageTextInputAreaGL = preedit_bounds;
  2841. CANDIDATEFORM candidate_form;
  2842. fillCandidateForm(caret_coord, preedit_bounds, &candidate_form);
  2843. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2844. // Win32 document says there may be up to 4 candidate windows.
  2845. // This magic number 4 appears only in the document, and
  2846. // there are no constant/macro for the value...
  2847. for (int i = 3; i >= 0; --i)
  2848. {
  2849. candidate_form.dwIndex = i;
  2850. LLWinImm::setCandidateWindow(himc, &candidate_form);
  2851. }
  2852. LLWinImm::releaseContext(mWindowHandle, himc);
  2853. }
  2854. }
  2855. void LLWindowWin32::interruptLanguageTextInput()
  2856. {
  2857. if (mPreeditor)
  2858. {
  2859. if (LLWinImm::isAvailable())
  2860. {
  2861. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2862. LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
  2863. LLWinImm::releaseContext(mWindowHandle, himc);
  2864. }
  2865. // Win32 document says there will be no composition string
  2866. // after NI_COMPOSITIONSTR returns.  The following call to
  2867. // resetPreedit should be a NOP unless IME goes mad...
  2868. mPreeditor->resetPreedit();
  2869. }
  2870. }
  2871. void LLWindowWin32::handleStartCompositionMessage()
  2872. {
  2873. // Let IME know the font to use in feedback UI.
  2874. LOGFONT logfont;
  2875. fillCompositionLogfont(&logfont);
  2876. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2877. LLWinImm::setCompositionFont(himc, &logfont);
  2878. LLWinImm::releaseContext(mWindowHandle, himc);
  2879. }
  2880. // Handle WM_IME_COMPOSITION message.
  2881. void LLWindowWin32::handleCompositionMessage(const U32 indexes)
  2882. {
  2883. BOOL needs_update = FALSE;
  2884. LLWString result_string;
  2885. LLWString preedit_string;
  2886. S32 preedit_string_utf16_length = 0;
  2887. LLPreeditor::segment_lengths_t preedit_segment_lengths;
  2888. LLPreeditor::standouts_t preedit_standouts;
  2889. // Step I: Receive details of preedits from IME.
  2890. HIMC himc = LLWinImm::getContext(mWindowHandle);
  2891. if (indexes & GCS_RESULTSTR)
  2892. {
  2893. LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0);
  2894. if (size >= 0)
  2895. {
  2896. const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
  2897. size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size);
  2898. if (size > 0)
  2899. {
  2900. result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
  2901. }
  2902. delete[] data;
  2903. needs_update = TRUE;
  2904. }
  2905. }
  2906. if (indexes & GCS_COMPSTR)
  2907. {
  2908. LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0);
  2909. if (size >= 0)
  2910. {
  2911. const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
  2912. size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size);
  2913. if (size > 0)
  2914. {
  2915. preedit_string_utf16_length = size / sizeof(WCHAR);
  2916. preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
  2917. }
  2918. delete[] data;
  2919. needs_update = TRUE;
  2920. }
  2921. }
  2922. if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0)
  2923. {
  2924. LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0);
  2925. if (size > 0)
  2926. {
  2927. const LPDWORD data = new DWORD[size / sizeof(DWORD)];
  2928. size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size);
  2929. if (size >= sizeof(DWORD) * 2
  2930. && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length)
  2931. {
  2932. preedit_segment_lengths.resize(size / sizeof(DWORD) - 1);
  2933. S32 offset = 0;
  2934. for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
  2935. {
  2936. const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]);
  2937. preedit_segment_lengths[i] = length;
  2938. offset += length;
  2939. }
  2940. }
  2941. delete[] data;
  2942. }
  2943. }
  2944. if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1)
  2945. {
  2946. LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0);
  2947. if (size > 0)
  2948. {
  2949. const LPBYTE data = new BYTE[size / sizeof(BYTE)];
  2950. size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size);
  2951. if (size == preedit_string_utf16_length)
  2952. {
  2953. preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
  2954. S32 offset = 0;
  2955. for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
  2956. {
  2957. if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset])
  2958. {
  2959. preedit_standouts[i] = TRUE;
  2960. }
  2961. offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]);
  2962. }
  2963. }
  2964. delete[] data;
  2965. }
  2966. }
  2967. S32 caret_position = preedit_string.length();
  2968. if (indexes & GCS_CURSORPOS)
  2969. {
  2970. const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0);
  2971. if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length)
  2972. {
  2973. caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16);
  2974. }
  2975. }
  2976. if (indexes == 0)
  2977. {
  2978. // I'm not sure this condition really happens, but
  2979. // Windows SDK document says it is an indication
  2980. // of "reset everything."
  2981. needs_update = TRUE;
  2982. }
  2983. LLWinImm::releaseContext(mWindowHandle, himc);
  2984. // Step II: Update the active preeditor.
  2985. if (needs_update)
  2986. {
  2987. mPreeditor->resetPreedit();
  2988. if (result_string.length() > 0)
  2989. {
  2990. for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++)
  2991. {
  2992. mPreeditor->handleUnicodeCharHere(*i);
  2993. }
  2994. }
  2995. if (preedit_string.length() == 0)
  2996.   {
  2997. preedit_segment_lengths.clear();
  2998. preedit_standouts.clear();
  2999. }
  3000. else
  3001. {
  3002. if (preedit_segment_lengths.size() == 0)
  3003. {
  3004. preedit_segment_lengths.assign(1, preedit_string.length());
  3005. }
  3006. if (preedit_standouts.size() == 0)
  3007. {
  3008. preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
  3009. }
  3010. }
  3011. mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
  3012. // Some IME doesn't query char position after WM_IME_COMPOSITION,
  3013. // so we need to update them actively.
  3014. updateLanguageTextInputArea();
  3015. }
  3016. }
  3017. // Given a text and a focus range, find_context finds and returns a
  3018. // surrounding context of the focused subtext.  A variable pointed
  3019. // to by offset receives the offset in llwchars of the beginning of
  3020. // the returned context string in the given wtext.
  3021. static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset)
  3022. {
  3023. static const S32 CONTEXT_EXCESS = 30; // This value is by experiences.
  3024. const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS);
  3025. S32 end = focus + focus_length;
  3026. while (end < e && 'n' != wtext[end])
  3027. {
  3028. end++;
  3029. }
  3030. const S32 s = llmax(0, focus - CONTEXT_EXCESS);
  3031. S32 start = focus;
  3032. while (start > s && 'n' != wtext[start - 1])
  3033. {
  3034. --start;
  3035. }
  3036. *offset = start;
  3037. return wtext.substr(start, end - start);
  3038. }
  3039. // final stage of handling drop requests - both from WM_DROPFILES message
  3040. // for files and via IDropTarget interface requests.
  3041. LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url )
  3042. {
  3043. return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url );
  3044. }
  3045. // Handle WM_IME_REQUEST message.
  3046. // If it handled the message, returns TRUE.  Otherwise, FALSE.
  3047. // When it handled the message, the value to be returned from
  3048. // the Window Procedure is set to *result.
  3049. BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
  3050. {
  3051. if ( mPreeditor )
  3052. {
  3053. switch (request)
  3054. {
  3055. case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx
  3056. {
  3057. LLCoordGL caret_coord;
  3058. LLRect preedit_bounds;
  3059. mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL);
  3060. CANDIDATEFORM *const form = (CANDIDATEFORM *)param;
  3061. DWORD const dwIndex = form->dwIndex;
  3062. fillCandidateForm(caret_coord, preedit_bounds, form);
  3063. form->dwIndex = dwIndex;
  3064. *result = 1;
  3065. return TRUE;
  3066. }
  3067. case IMR_QUERYCHARPOSITION:
  3068. {
  3069. IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param;
  3070. // char_position->dwCharPos counts in number of
  3071. // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the
  3072. // number to getPreeditLocation.  
  3073. const LLWString & wtext = mPreeditor->getPreeditString();
  3074. S32 preedit, preedit_length;
  3075. mPreeditor->getPreeditRange(&preedit, &preedit_length);
  3076. LLCoordGL caret_coord;
  3077. LLRect preedit_bounds, text_control;
  3078. const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos);
  3079. if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control))
  3080. {
  3081. LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL;
  3082. return FALSE;
  3083. }
  3084. fillCharPosition(caret_coord, preedit_bounds, text_control, char_position);
  3085. *result = 1;
  3086. return TRUE;
  3087. }
  3088. case IMR_COMPOSITIONFONT:
  3089. {
  3090. fillCompositionLogfont((LOGFONT *)param);
  3091. *result = 1;
  3092. return TRUE;
  3093. }
  3094. case IMR_RECONVERTSTRING:
  3095. {
  3096. mPreeditor->resetPreedit();
  3097. const LLWString & wtext = mPreeditor->getPreeditString();
  3098. S32 select, select_length;
  3099. mPreeditor->getSelectionRange(&select, &select_length);
  3100. S32 context_offset;
  3101. const LLWString context = find_context(wtext, select, select_length, &context_offset);
  3102. RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param;
  3103. const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string);
  3104. if (reconvert_string)
  3105. {
  3106. if (select_length == 0)
  3107. {
  3108. // Let the IME to decide the reconversion range, and
  3109. // adjust the reconvert_string structure accordingly.
  3110. HIMC himc = LLWinImm::getContext(mWindowHandle);
  3111. const BOOL adjusted = LLWinImm::setCompositionString(himc,
  3112. SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0);
  3113. LLWinImm::releaseContext(mWindowHandle, himc);
  3114. if (adjusted)
  3115. {
  3116. const llutf16string & text_utf16 = wstring_to_utf16str(context);
  3117. const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR);
  3118. const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen;
  3119. select = utf16str_wstring_length(text_utf16, new_preedit_start);
  3120. select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select;
  3121. select += context_offset;
  3122. }
  3123. }
  3124. mPreeditor->markAsPreedit(select, select_length);
  3125. }
  3126. *result = size;
  3127. return TRUE;
  3128. }
  3129. case IMR_CONFIRMRECONVERTSTRING:
  3130. {
  3131. *result = FALSE;
  3132. return TRUE;
  3133. }
  3134. case IMR_DOCUMENTFEED:
  3135. {
  3136. const LLWString & wtext = mPreeditor->getPreeditString();
  3137. S32 preedit, preedit_length;
  3138. mPreeditor->getPreeditRange(&preedit, &preedit_length);
  3139. S32 context_offset;
  3140. LLWString context = find_context(wtext, preedit, preedit_length, &context_offset);
  3141. preedit -= context_offset;
  3142. if (preedit_length)
  3143. {
  3144. // IMR_DOCUMENTFEED may be called when we have an active preedit.
  3145. // We should pass the context string *excluding* the preedit string.
  3146. // Otherwise, some IME are confused.
  3147. context.erase(preedit, preedit_length);
  3148. }
  3149. RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param;
  3150. *result = fillReconvertString(context, preedit, 0, reconvert_string);
  3151. return TRUE;
  3152. }
  3153. default:
  3154. return FALSE;
  3155. }
  3156. }
  3157. return FALSE;
  3158. }
  3159. //static
  3160. std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
  3161. {
  3162. // Fonts previously in getFontListSans() have moved to fonts.xml.
  3163. return std::vector<std::string>();
  3164. }
  3165. #endif // LL_WINDOWS