diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llwindow | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
37 files changed, 16262 insertions, 0 deletions
diff --git a/linden/indra/llwindow/files.darwin.lst b/linden/indra/llwindow/files.darwin.lst new file mode 100644 index 0000000..e8eca9b --- /dev/null +++ b/linden/indra/llwindow/files.darwin.lst | |||
@@ -0,0 +1,2 @@ | |||
1 | llwindow/llkeyboardmacosx.cpp | ||
2 | llwindow/llwindowmacosx.cpp | ||
diff --git a/linden/indra/llwindow/files.linux.lst b/linden/indra/llwindow/files.linux.lst new file mode 100644 index 0000000..e41ac2a --- /dev/null +++ b/linden/indra/llwindow/files.linux.lst | |||
@@ -0,0 +1,4 @@ | |||
1 | llwindow/llkeyboardsdl.cpp | ||
2 | llwindow/llwindowsdl.cpp | ||
3 | llwindow/llwindowlinux.cpp | ||
4 | llwindow/llwindowmesaheadless.cpp | ||
diff --git a/linden/indra/llwindow/files.lst b/linden/indra/llwindow/files.lst new file mode 100644 index 0000000..1c16b09 --- /dev/null +++ b/linden/indra/llwindow/files.lst | |||
@@ -0,0 +1,5 @@ | |||
1 | llwindow/lldxhardware.cpp | ||
2 | llwindow/llgl.cpp | ||
3 | llwindow/llkeyboard.cpp | ||
4 | llwindow/llwindow.cpp | ||
5 | llwindow/llwindowheadless.cpp | ||
diff --git a/linden/indra/llwindow/lldxhardware.cpp b/linden/indra/llwindow/lldxhardware.cpp new file mode 100644 index 0000000..5dd632b --- /dev/null +++ b/linden/indra/llwindow/lldxhardware.cpp | |||
@@ -0,0 +1,527 @@ | |||
1 | /** | ||
2 | * @file lldxhardware.cpp | ||
3 | * @brief LLDXHardware implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifdef LL_WINDOWS | ||
29 | |||
30 | // Culled from some Microsoft sample code | ||
31 | |||
32 | #include "linden_common.h" | ||
33 | |||
34 | #include <assert.h> | ||
35 | #include <dxdiag.h> | ||
36 | |||
37 | #include <boost/tokenizer.hpp> | ||
38 | |||
39 | #include "lldxhardware.h" | ||
40 | #include "llerror.h" | ||
41 | |||
42 | #include "llstring.h" | ||
43 | #include "llstl.h" | ||
44 | |||
45 | void (*gWriteDebug)(const char* msg) = NULL; | ||
46 | LLDXHardware gDXHardware; | ||
47 | |||
48 | //----------------------------------------------------------------------------- | ||
49 | // Defines, and constants | ||
50 | //----------------------------------------------------------------------------- | ||
51 | #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } | ||
52 | #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } | ||
53 | #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } | ||
54 | |||
55 | std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) | ||
56 | { | ||
57 | HRESULT hr; | ||
58 | VARIANT var; | ||
59 | WCHAR wszPropValue[256]; | ||
60 | |||
61 | VariantInit( &var ); | ||
62 | hr = containerp->GetProp(wszPropName, &var ); | ||
63 | if( SUCCEEDED(hr) ) | ||
64 | { | ||
65 | // Switch off the type. There's 4 different types: | ||
66 | switch( var.vt ) | ||
67 | { | ||
68 | case VT_UI4: | ||
69 | swprintf( wszPropValue, L"%d", var.ulVal ); | ||
70 | break; | ||
71 | case VT_I4: | ||
72 | swprintf( wszPropValue, L"%d", var.lVal ); | ||
73 | break; | ||
74 | case VT_BOOL: | ||
75 | wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); | ||
76 | break; | ||
77 | case VT_BSTR: | ||
78 | wcsncpy( wszPropValue, var.bstrVal, 255 ); | ||
79 | wszPropValue[255] = 0; | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | // Clear the variant (this is needed to free BSTR memory) | ||
84 | VariantClear( &var ); | ||
85 | |||
86 | return utf16str_to_utf8str(wszPropValue); | ||
87 | } | ||
88 | |||
89 | |||
90 | LLVersion::LLVersion() | ||
91 | { | ||
92 | mValid = FALSE; | ||
93 | S32 i; | ||
94 | for (i = 0; i < 4; i++) | ||
95 | { | ||
96 | mFields[i] = 0; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | BOOL LLVersion::set(const std::string &version_string) | ||
101 | { | ||
102 | S32 i; | ||
103 | for (i = 0; i < 4; i++) | ||
104 | { | ||
105 | mFields[i] = 0; | ||
106 | } | ||
107 | // Split the version string. | ||
108 | std::string str(version_string); | ||
109 | typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | ||
110 | boost::char_separator<char> sep(".", "", boost::keep_empty_tokens); | ||
111 | tokenizer tokens(str, sep); | ||
112 | |||
113 | tokenizer::iterator iter = tokens.begin(); | ||
114 | S32 count = 0; | ||
115 | for (;(iter != tokens.end()) && (count < 4);++iter) | ||
116 | { | ||
117 | mFields[count] = atoi(iter->c_str()); | ||
118 | count++; | ||
119 | } | ||
120 | if (count < 4) | ||
121 | { | ||
122 | //llwarns << "Potentially bogus version string!" << version_string << llendl; | ||
123 | for (i = 0; i < 4; i++) | ||
124 | { | ||
125 | mFields[i] = 0; | ||
126 | } | ||
127 | mValid = FALSE; | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | mValid = TRUE; | ||
132 | } | ||
133 | return mValid; | ||
134 | } | ||
135 | |||
136 | S32 LLVersion::getField(const S32 field_num) | ||
137 | { | ||
138 | if (!mValid) | ||
139 | { | ||
140 | return -1; | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | return mFields[field_num]; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | LLString LLDXDriverFile::dump() | ||
149 | { | ||
150 | if (gWriteDebug) | ||
151 | { | ||
152 | gWriteDebug("Filename:"); | ||
153 | gWriteDebug(mName.c_str()); | ||
154 | gWriteDebug("\n"); | ||
155 | gWriteDebug("Ver:"); | ||
156 | gWriteDebug(mVersionString.c_str()); | ||
157 | gWriteDebug("\n"); | ||
158 | gWriteDebug("Date:"); | ||
159 | gWriteDebug(mDateString.c_str()); | ||
160 | gWriteDebug("\n"); | ||
161 | } | ||
162 | llinfos << mFilepath << llendl; | ||
163 | llinfos << mName << llendl; | ||
164 | llinfos << mVersionString << llendl; | ||
165 | llinfos << mDateString << llendl; | ||
166 | |||
167 | return ""; | ||
168 | } | ||
169 | |||
170 | LLDXDevice::~LLDXDevice() | ||
171 | { | ||
172 | for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer()); | ||
173 | } | ||
174 | |||
175 | std::string LLDXDevice::dump() | ||
176 | { | ||
177 | if (gWriteDebug) | ||
178 | { | ||
179 | gWriteDebug("StartDevice\n"); | ||
180 | gWriteDebug("DeviceName:"); | ||
181 | gWriteDebug(mName.c_str()); | ||
182 | gWriteDebug("\n"); | ||
183 | gWriteDebug("PCIString:"); | ||
184 | gWriteDebug(mPCIString.c_str()); | ||
185 | gWriteDebug("\n"); | ||
186 | } | ||
187 | llinfos << llendl; | ||
188 | llinfos << "DeviceName:" << mName << llendl; | ||
189 | llinfos << "PCIString:" << mPCIString << llendl; | ||
190 | llinfos << "Drivers" << llendl; | ||
191 | llinfos << "-------" << llendl; | ||
192 | for (driver_file_map_t::iterator iter = mDriverFiles.begin(), | ||
193 | end = mDriverFiles.end(); | ||
194 | iter != end; iter++) | ||
195 | { | ||
196 | LLDXDriverFile *filep = iter->second; | ||
197 | filep->dump(); | ||
198 | } | ||
199 | if (gWriteDebug) | ||
200 | { | ||
201 | gWriteDebug("EndDevice\n"); | ||
202 | } | ||
203 | |||
204 | return ""; | ||
205 | } | ||
206 | |||
207 | LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver) | ||
208 | { | ||
209 | for (driver_file_map_t::iterator iter = mDriverFiles.begin(), | ||
210 | end = mDriverFiles.end(); | ||
211 | iter != end; iter++) | ||
212 | { | ||
213 | LLDXDriverFile *filep = iter->second; | ||
214 | if (!utf8str_compare_insensitive(filep->mName,driver)) | ||
215 | { | ||
216 | return filep; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | return NULL; | ||
221 | } | ||
222 | |||
223 | LLDXHardware::LLDXHardware() | ||
224 | { | ||
225 | mVRAM = 0; | ||
226 | gWriteDebug = NULL; | ||
227 | } | ||
228 | |||
229 | void LLDXHardware::cleanup() | ||
230 | { | ||
231 | for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer()); | ||
232 | } | ||
233 | |||
234 | LLString LLDXHardware::dumpDevices() | ||
235 | { | ||
236 | if (gWriteDebug) | ||
237 | { | ||
238 | gWriteDebug("\n"); | ||
239 | gWriteDebug("StartAllDevices\n"); | ||
240 | } | ||
241 | for (device_map_t::iterator iter = mDevices.begin(), | ||
242 | end = mDevices.end(); | ||
243 | iter != end; iter++) | ||
244 | { | ||
245 | LLDXDevice *devicep = iter->second; | ||
246 | devicep->dump(); | ||
247 | } | ||
248 | if (gWriteDebug) | ||
249 | { | ||
250 | gWriteDebug("EndAllDevices\n\n"); | ||
251 | } | ||
252 | return ""; | ||
253 | } | ||
254 | |||
255 | LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices) | ||
256 | { | ||
257 | // Iterate through different devices tokenized in devices string | ||
258 | std::string str(devices); | ||
259 | typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | ||
260 | boost::char_separator<char> sep("|", "", boost::keep_empty_tokens); | ||
261 | tokenizer tokens(str, sep); | ||
262 | |||
263 | tokenizer::iterator iter = tokens.begin(); | ||
264 | for (;iter != tokens.end();++iter) | ||
265 | { | ||
266 | std::string dev_str = *iter; | ||
267 | for (device_map_t::iterator iter = mDevices.begin(), | ||
268 | end = mDevices.end(); | ||
269 | iter != end; iter++) | ||
270 | { | ||
271 | LLDXDevice *devicep = iter->second; | ||
272 | if ((devicep->mVendorID == vendor) | ||
273 | && (devicep->mDeviceID == dev_str)) | ||
274 | { | ||
275 | return devicep; | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | |||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | BOOL LLDXHardware::getInfo(BOOL vram_only) | ||
284 | { | ||
285 | LLTimer hw_timer; | ||
286 | BOOL ok = FALSE; | ||
287 | HRESULT hr; | ||
288 | |||
289 | CoInitialize(NULL); | ||
290 | |||
291 | IDxDiagProvider *dx_diag_providerp = NULL; | ||
292 | IDxDiagContainer *dx_diag_rootp = NULL; | ||
293 | IDxDiagContainer *devices_containerp = NULL; | ||
294 | IDxDiagContainer *system_device_containerp= NULL; | ||
295 | IDxDiagContainer *device_containerp = NULL; | ||
296 | IDxDiagContainer *file_containerp = NULL; | ||
297 | IDxDiagContainer *driver_containerp = NULL; | ||
298 | |||
299 | // CoCreate a IDxDiagProvider* | ||
300 | llinfos << "CoCreateInstance IID_IDxDiagProvider" << llendl; | ||
301 | hr = CoCreateInstance(CLSID_DxDiagProvider, | ||
302 | NULL, | ||
303 | CLSCTX_INPROC_SERVER, | ||
304 | IID_IDxDiagProvider, | ||
305 | (LPVOID*) &dx_diag_providerp); | ||
306 | |||
307 | if (FAILED(hr)) | ||
308 | { | ||
309 | llwarns << "No DXDiag provider found! DirectX 9 not installed!" << llendl; | ||
310 | gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); | ||
311 | goto LCleanup; | ||
312 | } | ||
313 | if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed | ||
314 | { | ||
315 | // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize | ||
316 | // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are | ||
317 | // digital signed as logo'd by WHQL which may connect via internet to update | ||
318 | // WHQL certificates. | ||
319 | DXDIAG_INIT_PARAMS dx_diag_init_params; | ||
320 | ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); | ||
321 | |||
322 | dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); | ||
323 | dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; | ||
324 | dx_diag_init_params.bAllowWHQLChecks = TRUE; | ||
325 | dx_diag_init_params.pReserved = NULL; | ||
326 | |||
327 | llinfos << "dx_diag_providerp->Initialize" << llendl; | ||
328 | hr = dx_diag_providerp->Initialize(&dx_diag_init_params); | ||
329 | if(FAILED(hr)) | ||
330 | { | ||
331 | goto LCleanup; | ||
332 | } | ||
333 | |||
334 | llinfos << "dx_diag_providerp->GetRootContainer" << llendl; | ||
335 | hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); | ||
336 | if(FAILED(hr) || !dx_diag_rootp) | ||
337 | { | ||
338 | goto LCleanup; | ||
339 | } | ||
340 | |||
341 | HRESULT hr; | ||
342 | |||
343 | // Get display driver information | ||
344 | llinfos << "dx_diag_rootp->GetChildContainer" << llendl; | ||
345 | hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); | ||
346 | if(FAILED(hr) || !devices_containerp) | ||
347 | { | ||
348 | goto LCleanup; | ||
349 | } | ||
350 | |||
351 | // Get device 0 | ||
352 | llinfos << "devices_containerp->GetChildContainer" << llendl; | ||
353 | hr = devices_containerp->GetChildContainer(L"0", &device_containerp); | ||
354 | if(FAILED(hr) || !device_containerp) | ||
355 | { | ||
356 | goto LCleanup; | ||
357 | } | ||
358 | |||
359 | // Get the English VRAM string | ||
360 | std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); | ||
361 | |||
362 | // We don't need the device any more | ||
363 | SAFE_RELEASE(device_containerp); | ||
364 | |||
365 | // Dump the string as an int into the structure | ||
366 | char *stopstring; | ||
367 | mVRAM = strtol(ram_str.c_str(), &stopstring, 10); | ||
368 | llinfos << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << llendl; | ||
369 | |||
370 | if (vram_only) | ||
371 | { | ||
372 | ok = TRUE; | ||
373 | goto LCleanup; | ||
374 | } | ||
375 | |||
376 | // Now let's get device and driver information | ||
377 | // Get the IDxDiagContainer object called "DxDiag_SystemDevices". | ||
378 | // This call may take some time while dxdiag gathers the info. | ||
379 | DWORD num_devices = 0; | ||
380 | WCHAR wszContainer[256]; | ||
381 | llinfos << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << llendl; | ||
382 | hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp); | ||
383 | if (FAILED(hr)) | ||
384 | { | ||
385 | goto LCleanup; | ||
386 | } | ||
387 | |||
388 | hr = system_device_containerp->GetNumberOfChildContainers(&num_devices); | ||
389 | if (FAILED(hr)) | ||
390 | { | ||
391 | goto LCleanup; | ||
392 | } | ||
393 | |||
394 | llinfos << "DX9 iterating over devices" << llendl; | ||
395 | S32 device_num = 0; | ||
396 | for (device_num = 0; device_num < (S32)num_devices; device_num++) | ||
397 | { | ||
398 | hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256); | ||
399 | if (FAILED(hr)) | ||
400 | { | ||
401 | goto LCleanup; | ||
402 | } | ||
403 | |||
404 | hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp); | ||
405 | if (FAILED(hr) || device_containerp == NULL) | ||
406 | { | ||
407 | goto LCleanup; | ||
408 | } | ||
409 | |||
410 | std::string device_name = get_string(device_containerp, L"szDescription"); | ||
411 | std::string device_id = get_string(device_containerp, L"szDeviceID"); | ||
412 | |||
413 | LLDXDevice *dxdevicep = new LLDXDevice; | ||
414 | dxdevicep->mName = device_name; | ||
415 | dxdevicep->mPCIString = device_id; | ||
416 | mDevices[dxdevicep->mPCIString] = dxdevicep; | ||
417 | |||
418 | // Split the PCI string based on vendor, device, subsys, rev. | ||
419 | std::string str(device_id); | ||
420 | typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | ||
421 | boost::char_separator<char> sep("&\\", "", boost::keep_empty_tokens); | ||
422 | tokenizer tokens(str, sep); | ||
423 | |||
424 | tokenizer::iterator iter = tokens.begin(); | ||
425 | S32 count = 0; | ||
426 | BOOL valid = TRUE; | ||
427 | for (;(iter != tokens.end()) && (count < 3);++iter) | ||
428 | { | ||
429 | switch (count) | ||
430 | { | ||
431 | case 0: | ||
432 | if (strcmp(iter->c_str(), "PCI")) | ||
433 | { | ||
434 | valid = FALSE; | ||
435 | } | ||
436 | break; | ||
437 | case 1: | ||
438 | dxdevicep->mVendorID = iter->c_str(); | ||
439 | break; | ||
440 | case 2: | ||
441 | dxdevicep->mDeviceID = iter->c_str(); | ||
442 | break; | ||
443 | default: | ||
444 | // Ignore it | ||
445 | break; | ||
446 | } | ||
447 | count++; | ||
448 | } | ||
449 | |||
450 | |||
451 | // Now, iterate through the related drivers | ||
452 | hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp); | ||
453 | if (FAILED(hr) || !driver_containerp) | ||
454 | { | ||
455 | goto LCleanup; | ||
456 | } | ||
457 | |||
458 | DWORD num_files = 0; | ||
459 | hr = driver_containerp->GetNumberOfChildContainers(&num_files); | ||
460 | if (FAILED(hr)) | ||
461 | { | ||
462 | goto LCleanup; | ||
463 | } | ||
464 | |||
465 | S32 file_num = 0; | ||
466 | for (file_num = 0; file_num < (S32)num_files; file_num++ ) | ||
467 | { | ||
468 | hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256); | ||
469 | if (FAILED(hr)) | ||
470 | { | ||
471 | goto LCleanup; | ||
472 | } | ||
473 | |||
474 | hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp); | ||
475 | if (FAILED(hr) || file_containerp == NULL) | ||
476 | { | ||
477 | goto LCleanup; | ||
478 | } | ||
479 | |||
480 | std::string driver_path = get_string(file_containerp, L"szPath"); | ||
481 | std::string driver_name = get_string(file_containerp, L"szName"); | ||
482 | std::string driver_version = get_string(file_containerp, L"szVersion"); | ||
483 | std::string driver_date = get_string(file_containerp, L"szDatestampEnglish"); | ||
484 | |||
485 | LLDXDriverFile *dxdriverfilep = new LLDXDriverFile; | ||
486 | dxdriverfilep->mName = driver_name; | ||
487 | dxdriverfilep->mFilepath= driver_path; | ||
488 | dxdriverfilep->mVersionString = driver_version; | ||
489 | dxdriverfilep->mVersion.set(driver_version); | ||
490 | dxdriverfilep->mDateString = driver_date; | ||
491 | |||
492 | dxdevicep->mDriverFiles[driver_name] = dxdriverfilep; | ||
493 | |||
494 | SAFE_RELEASE(file_containerp); | ||
495 | } | ||
496 | SAFE_RELEASE(device_containerp); | ||
497 | } | ||
498 | } | ||
499 | |||
500 | dumpDevices(); | ||
501 | ok = TRUE; | ||
502 | |||
503 | LCleanup: | ||
504 | if (!ok) | ||
505 | { | ||
506 | llwarns << "DX9 probe failed" << llendl; | ||
507 | gWriteDebug("DX9 probe failed\n"); | ||
508 | } | ||
509 | |||
510 | SAFE_RELEASE(file_containerp); | ||
511 | SAFE_RELEASE(driver_containerp); | ||
512 | SAFE_RELEASE(device_containerp); | ||
513 | SAFE_RELEASE(devices_containerp); | ||
514 | SAFE_RELEASE(dx_diag_rootp); | ||
515 | SAFE_RELEASE(dx_diag_providerp); | ||
516 | |||
517 | CoUninitialize(); | ||
518 | |||
519 | return ok; | ||
520 | } | ||
521 | |||
522 | void LLDXHardware::setWriteDebugFunc(void (*func)(const char*)) | ||
523 | { | ||
524 | gWriteDebug = func; | ||
525 | } | ||
526 | |||
527 | #endif | ||
diff --git a/linden/indra/llwindow/lldxhardware.h b/linden/indra/llwindow/lldxhardware.h new file mode 100644 index 0000000..5d8b925 --- /dev/null +++ b/linden/indra/llwindow/lldxhardware.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /** | ||
2 | * @file lldxhardware.h | ||
3 | * @brief LLDXHardware definition | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLDXHARDWARE_H | ||
29 | #define LL_LLDXHARDWARE_H | ||
30 | |||
31 | #include <map> | ||
32 | |||
33 | #include "stdtypes.h" | ||
34 | #include "llstring.h" | ||
35 | |||
36 | class LLVersion | ||
37 | { | ||
38 | public: | ||
39 | LLVersion(); | ||
40 | BOOL set(const std::string &version_string); | ||
41 | S32 getField(const S32 field_num); | ||
42 | protected: | ||
43 | std::string mVersionString; | ||
44 | S32 mFields[4]; | ||
45 | BOOL mValid; | ||
46 | }; | ||
47 | |||
48 | class LLDXDriverFile | ||
49 | { | ||
50 | public: | ||
51 | LLString dump(); | ||
52 | |||
53 | public: | ||
54 | std::string mFilepath; | ||
55 | std::string mName; | ||
56 | std::string mVersionString; | ||
57 | LLVersion mVersion; | ||
58 | std::string mDateString; | ||
59 | }; | ||
60 | |||
61 | class LLDXDevice | ||
62 | { | ||
63 | public: | ||
64 | ~LLDXDevice(); | ||
65 | std::string dump(); | ||
66 | |||
67 | LLDXDriverFile *findDriver(const std::string &driver); | ||
68 | public: | ||
69 | std::string mName; | ||
70 | std::string mPCIString; | ||
71 | std::string mVendorID; | ||
72 | std::string mDeviceID; | ||
73 | |||
74 | typedef std::map<std::string, LLDXDriverFile *> driver_file_map_t; | ||
75 | driver_file_map_t mDriverFiles; | ||
76 | }; | ||
77 | |||
78 | |||
79 | class LLDXHardware | ||
80 | { | ||
81 | public: | ||
82 | LLDXHardware(); | ||
83 | void setWriteDebugFunc(void (*func)(const char*)); | ||
84 | void cleanup(); | ||
85 | |||
86 | // Returns TRUE on success. | ||
87 | // vram_only TRUE does a "light" probe. | ||
88 | BOOL getInfo(BOOL vram_only); | ||
89 | |||
90 | S32 getVRAM() const { return mVRAM; } | ||
91 | |||
92 | // Find a particular device that matches the following specs. | ||
93 | // Empty strings indicate that you don't care. | ||
94 | // You can separate multiple devices with '|' chars to indicate you want | ||
95 | // ANY of them to match and return. | ||
96 | LLDXDevice *findDevice(const std::string &vendor, const std::string &devices); | ||
97 | |||
98 | LLString dumpDevices(); | ||
99 | public: | ||
100 | typedef std::map<std::string, LLDXDevice *> device_map_t; | ||
101 | device_map_t mDevices; | ||
102 | protected: | ||
103 | S32 mVRAM; | ||
104 | }; | ||
105 | |||
106 | extern void (*gWriteDebug)(const char* msg); | ||
107 | extern LLDXHardware gDXHardware; | ||
108 | |||
109 | #endif // LL_LLDXHARDWARE_H | ||
diff --git a/linden/indra/llwindow/llgl.cpp b/linden/indra/llwindow/llgl.cpp new file mode 100644 index 0000000..547a353 --- /dev/null +++ b/linden/indra/llwindow/llgl.cpp | |||
@@ -0,0 +1,1378 @@ | |||
1 | /** | ||
2 | * @file llgl.cpp | ||
3 | * @brief LLGL implementation | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | // This file sets some global GL parameters, and implements some | ||
29 | // useful functions for GL operations. | ||
30 | |||
31 | #define GLH_EXT_SINGLE_FILE | ||
32 | |||
33 | #include "linden_common.h" | ||
34 | |||
35 | #include "llsys.h" | ||
36 | |||
37 | #include "llgl.h" | ||
38 | |||
39 | #include "llerror.h" | ||
40 | #include "llquaternion.h" | ||
41 | #include "llmath.h" | ||
42 | #include "m4math.h" | ||
43 | #include "llstring.h" | ||
44 | |||
45 | #include "llglheaders.h" | ||
46 | |||
47 | |||
48 | #if LL_LINUX && !LL_MESA_HEADLESS | ||
49 | // The __APPLE__ hack is to make glh_extensions.h not symbol-clash horribly | ||
50 | # define __APPLE__ | ||
51 | # include "GL/glh_extensions.h" | ||
52 | # undef __APPLE__ | ||
53 | |||
54 | /* Although SDL very likely ends up calling glXGetProcAddress() itself, | ||
55 | if we do it ourselves then we avoid getting bogus addresses back on | ||
56 | some systems. Weird. */ | ||
57 | /*# include "SDL/SDL.h" | ||
58 | # define GLH_EXT_GET_PROC_ADDRESS(p) SDL_GL_GetProcAddress(p) */ | ||
59 | #define GLX_GLXEXT_PROTOTYPES 1 | ||
60 | # include "GL/glx.h" | ||
61 | # include "GL/glxext.h" | ||
62 | // Use glXGetProcAddressARB instead of glXGetProcAddress - the ARB symbol | ||
63 | // is considered 'legacy' but works on more machines. | ||
64 | # define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB((const GLubyte*)(p)) | ||
65 | #endif // LL_LINUX && !LL_MESA_HEADLESS | ||
66 | |||
67 | |||
68 | #ifdef _DEBUG | ||
69 | //#define GL_STATE_VERIFY | ||
70 | #endif | ||
71 | |||
72 | BOOL gClothRipple = FALSE; | ||
73 | BOOL gNoRender = FALSE; | ||
74 | |||
75 | |||
76 | #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS | ||
77 | // ATI prototypes | ||
78 | // vertex blending prototypes | ||
79 | PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL; | ||
80 | PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL; | ||
81 | PFNGLWEIGHTFVARBPROC glWeightfvARB = NULL; | ||
82 | |||
83 | // Vertex buffer object prototypes | ||
84 | PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; | ||
85 | PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; | ||
86 | PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; | ||
87 | PFNGLISBUFFERARBPROC glIsBufferARB = NULL; | ||
88 | PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; | ||
89 | PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL; | ||
90 | PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB = NULL; | ||
91 | PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL; | ||
92 | PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL; | ||
93 | PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL; | ||
94 | PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL; | ||
95 | |||
96 | // vertex object prototypes | ||
97 | PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL; | ||
98 | PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL; | ||
99 | PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI = NULL; | ||
100 | PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI = NULL; | ||
101 | PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI = NULL; | ||
102 | PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI = NULL; | ||
103 | PFNGLARRAYOBJECTATIPROC glArrayObjectATI = NULL; | ||
104 | PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI = NULL; | ||
105 | PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI = NULL; | ||
106 | PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI = NULL; | ||
107 | PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI = NULL; | ||
108 | PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI = NULL; | ||
109 | PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI = NULL; | ||
110 | |||
111 | // GL_ARB_occlusion_query | ||
112 | PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL; | ||
113 | PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL; | ||
114 | PFNGLISQUERYARBPROC glIsQueryARB = NULL; | ||
115 | PFNGLBEGINQUERYARBPROC glBeginQueryARB = NULL; | ||
116 | PFNGLENDQUERYARBPROC glEndQueryARB = NULL; | ||
117 | PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL; | ||
118 | PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL; | ||
119 | PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL; | ||
120 | |||
121 | //shader object prototypes | ||
122 | PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL; | ||
123 | PFNGLGETHANDLEARBPROC glGetHandleARB = NULL; | ||
124 | PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL; | ||
125 | PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL; | ||
126 | PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL; | ||
127 | PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL; | ||
128 | PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL; | ||
129 | PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL; | ||
130 | PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL; | ||
131 | PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL; | ||
132 | PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = NULL; | ||
133 | PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL; | ||
134 | PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL; | ||
135 | PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL; | ||
136 | PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL; | ||
137 | PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL; | ||
138 | PFNGLUNIFORM2IARBPROC glUniform2iARB = NULL; | ||
139 | PFNGLUNIFORM3IARBPROC glUniform3iARB = NULL; | ||
140 | PFNGLUNIFORM4IARBPROC glUniform4iARB = NULL; | ||
141 | PFNGLUNIFORM1FVARBPROC glUniform1fvARB = NULL; | ||
142 | PFNGLUNIFORM2FVARBPROC glUniform2fvARB = NULL; | ||
143 | PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL; | ||
144 | PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL; | ||
145 | PFNGLUNIFORM1IVARBPROC glUniform1ivARB = NULL; | ||
146 | PFNGLUNIFORM2IVARBPROC glUniform2ivARB = NULL; | ||
147 | PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL; | ||
148 | PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL; | ||
149 | PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL; | ||
150 | PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL; | ||
151 | PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL; | ||
152 | PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL; | ||
153 | PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL; | ||
154 | PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL; | ||
155 | PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL; | ||
156 | PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL; | ||
157 | PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL; | ||
158 | PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL; | ||
159 | PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL; | ||
160 | PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL; | ||
161 | |||
162 | // vertex shader prototypes | ||
163 | #if LL_LINUX | ||
164 | PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL; | ||
165 | PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL; | ||
166 | PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL; | ||
167 | PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB = NULL; | ||
168 | PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB = NULL; | ||
169 | PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB = NULL; | ||
170 | PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB = NULL; | ||
171 | PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB = NULL; | ||
172 | PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB = NULL; | ||
173 | PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB = NULL; | ||
174 | PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB = NULL; | ||
175 | PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB = NULL; | ||
176 | PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB = NULL; | ||
177 | PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB = NULL; | ||
178 | PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL; | ||
179 | PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL; | ||
180 | PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL; | ||
181 | PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL; | ||
182 | #endif // LL_LINUX | ||
183 | PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL; | ||
184 | PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL; | ||
185 | PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL; | ||
186 | PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL; | ||
187 | PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL; | ||
188 | PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL; | ||
189 | PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL; | ||
190 | #if LL_LINUX | ||
191 | PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL; | ||
192 | PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL; | ||
193 | PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL; | ||
194 | PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB = NULL; | ||
195 | PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB = NULL; | ||
196 | PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB = NULL; | ||
197 | PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB = NULL; | ||
198 | PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB = NULL; | ||
199 | PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB = NULL; | ||
200 | PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB = NULL; | ||
201 | PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB = NULL; | ||
202 | PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = NULL; | ||
203 | PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = NULL; | ||
204 | PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = NULL; | ||
205 | PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL; | ||
206 | PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL; | ||
207 | PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL; | ||
208 | PFNGLGENPROGRAMSARBPROC glGenProgramsARB = NULL; | ||
209 | PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB = NULL; | ||
210 | PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB = NULL; | ||
211 | PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL; | ||
212 | PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL; | ||
213 | PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB = NULL; | ||
214 | PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB = NULL; | ||
215 | PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL; | ||
216 | PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL; | ||
217 | PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB = NULL; | ||
218 | PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL; | ||
219 | PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB = NULL; | ||
220 | PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL; | ||
221 | PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL; | ||
222 | PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL; | ||
223 | PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB = NULL; | ||
224 | PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL; | ||
225 | PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL; | ||
226 | PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL; | ||
227 | PFNGLISPROGRAMARBPROC glIsProgramARB = NULL; | ||
228 | #endif // LL_LINUX | ||
229 | PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL; | ||
230 | PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; | ||
231 | PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; | ||
232 | |||
233 | #if LL_WINDOWS | ||
234 | PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; | ||
235 | #endif | ||
236 | |||
237 | #if LL_LINUX | ||
238 | PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL; | ||
239 | #endif // LL_LINUX | ||
240 | |||
241 | #endif | ||
242 | |||
243 | LLGLManager gGLManager; | ||
244 | |||
245 | LLGLManager::LLGLManager() | ||
246 | { | ||
247 | mInited = FALSE; | ||
248 | mIsDisabled = FALSE; | ||
249 | mHasCubeMap = FALSE; | ||
250 | mHasMultitexture = FALSE; | ||
251 | mHasAnyAGP = FALSE; | ||
252 | mHasMipMapGeneration = FALSE; | ||
253 | mHasAnisotropic = FALSE; | ||
254 | mHasCompressedTextures = FALSE; | ||
255 | mHasNVVertexArrayRange = FALSE; | ||
256 | mHasNVFence = FALSE; | ||
257 | mHasARBEnvCombine = FALSE; | ||
258 | mHasATIVAO = FALSE; | ||
259 | mIsRadeon8500 = FALSE; | ||
260 | mIsRadeon9700 = FALSE; | ||
261 | mIsMobilityRadeon9000 = FALSE; | ||
262 | mIsGF2or4MX = FALSE; | ||
263 | mIsGF3 = FALSE; | ||
264 | mIsGFFX = FALSE; | ||
265 | mIsATI = FALSE; | ||
266 | mATIOffsetVerticalLines = FALSE; | ||
267 | mHasVertexShader = FALSE; | ||
268 | mHasFragmentShader = FALSE; | ||
269 | mHasShaderObjects = FALSE; | ||
270 | |||
271 | #if LL_WINDOWS | ||
272 | mHasWGLARBPixelFormat = FALSE; | ||
273 | #endif // LL_WINDOWS | ||
274 | |||
275 | #if LL_DARWIN | ||
276 | mHasAPPLEVertexArrayRange = FALSE; | ||
277 | mHasAPPLEFence = FALSE; | ||
278 | mHasAPPLEVAO = FALSE; | ||
279 | #endif | ||
280 | |||
281 | mIsNVIDIA = FALSE; | ||
282 | mIsIntel = FALSE; | ||
283 | |||
284 | mDriverVersionMajor = 1; | ||
285 | mDriverVersionMinor = 0; | ||
286 | mDriverVersionRelease = 0; | ||
287 | mGLVersion = 1.0f; | ||
288 | |||
289 | mNumTextureUnits = 1; | ||
290 | mVRAM = 0; | ||
291 | mGLMaxVertexRange = 0; | ||
292 | mGLMaxIndexRange = 0; | ||
293 | mSoftwareBlendSSE = TRUE; | ||
294 | } | ||
295 | |||
296 | //--------------------------------------------------------------------- | ||
297 | // Global initialization for GL | ||
298 | //--------------------------------------------------------------------- | ||
299 | void LLGLManager::initWGL() | ||
300 | { | ||
301 | mHasPBuffer = FALSE; | ||
302 | #if LL_WINDOWS && !LL_MESA_HEADLESS | ||
303 | if (!glh_init_extensions("WGL_ARB_pixel_format")) | ||
304 | { | ||
305 | llwarns << "No ARB pixel format extensions" << llendl; | ||
306 | } | ||
307 | |||
308 | if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) | ||
309 | { | ||
310 | GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); | ||
311 | } | ||
312 | |||
313 | mHasWGLARBPixelFormat = glh_init_extensions("WGL_ARB_pbuffer"); | ||
314 | if( !mHasWGLARBPixelFormat ) | ||
315 | { | ||
316 | llwarns << "No ARB WGL PBuffer extensions" << llendl; | ||
317 | } | ||
318 | |||
319 | if( !glh_init_extensions("WGL_ARB_render_texture") ) | ||
320 | { | ||
321 | llwarns << "No ARB WGL render texture extensions" << llendl; | ||
322 | } | ||
323 | |||
324 | mHasPBuffer = ExtensionExists("WGL_ARB_pbuffer", gGLHExts.mSysExts) && | ||
325 | ExtensionExists("WGL_ARB_render_texture", gGLHExts.mSysExts) && | ||
326 | ExtensionExists("WGL_ARB_pixel_format", gGLHExts.mSysExts); | ||
327 | #endif | ||
328 | } | ||
329 | |||
330 | // return false if unable (or unwilling due to old drivers) to init GL | ||
331 | bool LLGLManager::initGL() | ||
332 | { | ||
333 | if (mInited) | ||
334 | { | ||
335 | llerrs << "Calling init on LLGLManager after already initialized!" << llendl; | ||
336 | } | ||
337 | |||
338 | GLint alpha_bits; | ||
339 | glGetIntegerv( GL_ALPHA_BITS, &alpha_bits ); | ||
340 | if( 8 != alpha_bits ) | ||
341 | { | ||
342 | llwarns << "Frame buffer has less than 8 bits of alpha. Avatar texture compositing will fail." << llendl; | ||
343 | } | ||
344 | |||
345 | // This function uses at least one variable that's initialized below. | ||
346 | // Moved this call down to after we figure out which card we're dealing with. -- MBW 2003.10.07 | ||
347 | // initExtensions(); | ||
348 | |||
349 | // Extract video card strings and convert to upper case to | ||
350 | // work around driver-to-driver variation in capitalization. | ||
351 | mGLVendor = LLString((const char *)glGetString(GL_VENDOR)); | ||
352 | LLString::toUpper(mGLVendor); | ||
353 | |||
354 | mGLRenderer = LLString((const char *)glGetString(GL_RENDERER)); | ||
355 | LLString::toUpper(mGLRenderer); | ||
356 | |||
357 | parse_gl_version( &mDriverVersionMajor, | ||
358 | &mDriverVersionMinor, | ||
359 | &mDriverVersionRelease, | ||
360 | &mDriverVersionVendorString ); | ||
361 | |||
362 | mGLVersion = mDriverVersionMajor + mDriverVersionMinor * .1f; | ||
363 | |||
364 | // Trailing space necessary to keep "nVidia Corpor_ati_on" cards | ||
365 | // from being recognized as ATI. | ||
366 | if (mGLVendor.substr(0,4) == "ATI ") | ||
367 | { | ||
368 | BOOL mobile = FALSE; | ||
369 | if (mGLRenderer.find("MOBILITY") != LLString::npos) | ||
370 | { | ||
371 | mobile = TRUE; | ||
372 | } | ||
373 | mIsATI = TRUE; | ||
374 | if ( mGLRenderer.find("9500") != LLString::npos | ||
375 | || mGLRenderer.find("9600") != LLString::npos | ||
376 | || mGLRenderer.find("9700") != LLString::npos | ||
377 | || mGLRenderer.find("9800") != LLString::npos ) | ||
378 | { | ||
379 | mIsRadeon9700 = TRUE; | ||
380 | } | ||
381 | else if (mGLRenderer.find("8500") != LLString::npos | ||
382 | || mGLRenderer.find( "9000") != LLString::npos | ||
383 | || mGLRenderer.find("9100") != LLString::npos | ||
384 | || mGLRenderer.find("9200") != LLString::npos) | ||
385 | { | ||
386 | mIsRadeon8500 = TRUE; | ||
387 | if (mobile && mGLRenderer.find("9000") != LLString::npos) | ||
388 | { | ||
389 | mIsMobilityRadeon9000 = TRUE; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | #if LL_WINDOWS && !LL_MESA_HEADLESS | ||
394 | if (mIsRadeon9700 && mDriverVersionRelease < 3833) | ||
395 | { | ||
396 | return false; // Unsupported hardware | ||
397 | } | ||
398 | |||
399 | if (mDriverVersionRelease < 3842) | ||
400 | { | ||
401 | mATIOffsetVerticalLines = TRUE; | ||
402 | } | ||
403 | #endif // LL_WINDOWS | ||
404 | } | ||
405 | else if (mGLVendor.find("NVIDIA ") != LLString::npos) | ||
406 | { | ||
407 | mIsNVIDIA = TRUE; | ||
408 | if ( mGLRenderer.find("GEFORCE4 MX") != LLString::npos | ||
409 | || mGLRenderer.find("GEFORCE2") != LLString::npos | ||
410 | || mGLRenderer.find("GEFORCE 2") != LLString::npos | ||
411 | || mGLRenderer.find("GEFORCE4 460 GO") != LLString::npos | ||
412 | || mGLRenderer.find("GEFORCE4 440 GO") != LLString::npos | ||
413 | || mGLRenderer.find("GEFORCE4 420 GO") != LLString::npos) | ||
414 | { | ||
415 | mIsGF2or4MX = TRUE; | ||
416 | } | ||
417 | else if (mGLRenderer.find("GEFORCE FX") != LLString::npos | ||
418 | || mGLRenderer.find("QUADRO FX") != LLString::npos | ||
419 | || mGLRenderer.find("NV34") != LLString::npos) | ||
420 | { | ||
421 | mIsGFFX = TRUE; | ||
422 | } | ||
423 | else if(mGLRenderer.find("GEFORCE3") != LLString::npos) | ||
424 | { | ||
425 | mIsGF3 = TRUE; | ||
426 | } | ||
427 | |||
428 | } | ||
429 | else if (mGLVendor.find("INTEL") != LLString::npos) | ||
430 | { | ||
431 | mIsIntel = TRUE; | ||
432 | } | ||
433 | |||
434 | // This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture. | ||
435 | initExtensions(); | ||
436 | |||
437 | if (mHasMultitexture) | ||
438 | { | ||
439 | GLint num_tex_units; | ||
440 | glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &num_tex_units); | ||
441 | mNumTextureUnits = llmin(num_tex_units, (GLint)MAX_GL_TEXTURE_UNITS); | ||
442 | if (mIsIntel) | ||
443 | { | ||
444 | mNumTextureUnits = llmin(mNumTextureUnits, 2); | ||
445 | } | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | // We don't support cards that don't support the GL_ARB_multitexture extension | ||
450 | llwarns << "GL Drivers do not support GL_ARB_multitexture" << llendl; | ||
451 | return false; | ||
452 | } | ||
453 | |||
454 | |||
455 | initGLStates(); | ||
456 | return true; | ||
457 | } | ||
458 | |||
459 | LLString LLGLManager::getGLInfoString() | ||
460 | { | ||
461 | LLString info_str; | ||
462 | LLString all_exts, line; | ||
463 | |||
464 | info_str += LLString("GL_VENDOR ") + LLString((const char *)glGetString(GL_VENDOR)) + LLString("\n"); | ||
465 | info_str += LLString("GL_RENDERER ") + LLString((const char *)glGetString(GL_RENDERER)) + LLString("\n"); | ||
466 | info_str += LLString("GL_VERSION ") + LLString((const char *)glGetString(GL_VERSION)) + LLString("\n"); | ||
467 | |||
468 | #if !LL_MESA_HEADLESS | ||
469 | all_exts = (const char *)gGLHExts.mSysExts; | ||
470 | LLString::replaceChar(all_exts, ' ', '\n'); | ||
471 | info_str += LLString("GL_EXTENSIONS:\n") + all_exts + LLString("\n"); | ||
472 | #endif | ||
473 | |||
474 | return info_str; | ||
475 | } | ||
476 | |||
477 | LLString LLGLManager::getRawGLString() | ||
478 | { | ||
479 | LLString gl_string; | ||
480 | gl_string.assign((char*)glGetString(GL_VENDOR)); | ||
481 | gl_string.append(" "); | ||
482 | gl_string.append((char*)glGetString(GL_RENDERER)); | ||
483 | return gl_string; | ||
484 | } | ||
485 | |||
486 | void LLGLManager::shutdownGL() | ||
487 | { | ||
488 | if (mInited) | ||
489 | { | ||
490 | stop_glerror(); | ||
491 | mInited = FALSE; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | // these are used to turn software blending on. They appear in the Debug/Avatar menu | ||
496 | // presence of vertex skinning/blending or vertex programs will set these to FALSE by default. | ||
497 | |||
498 | extern LLCPUInfo gSysCPU; | ||
499 | |||
500 | void LLGLManager::initExtensions() | ||
501 | { | ||
502 | mSoftwareBlendSSE = gSysCPU.hasSSE(); | ||
503 | |||
504 | #if LL_MESA_HEADLESS | ||
505 | # if GL_ARB_multitexture | ||
506 | mHasMultitexture = TRUE; | ||
507 | # else | ||
508 | mHasMultitexture = FALSE; | ||
509 | # endif | ||
510 | # if GL_ARB_texture_env_combine | ||
511 | mHasARBEnvCombine = TRUE; | ||
512 | # else | ||
513 | mHasARBEnvCombine = FALSE; | ||
514 | # endif | ||
515 | # if GL_ARB_texture_compression | ||
516 | mHasCompressedTextures = TRUE; | ||
517 | # else | ||
518 | mHasCompressedTextures = FALSE; | ||
519 | # endif | ||
520 | # if GL_ARB_vertex_buffer_object | ||
521 | mHasVertexBufferObject = TRUE; | ||
522 | # else | ||
523 | mHasVertexBufferObject = FALSE; | ||
524 | # endif | ||
525 | mHasMipMapGeneration = FALSE; | ||
526 | mHasPalettedTextures = FALSE; | ||
527 | mHasNVVertexArrayRange = FALSE; | ||
528 | mHasNVFence = FALSE; | ||
529 | mHasSeparateSpecularColor = FALSE; | ||
530 | mHasAnisotropic = FALSE; | ||
531 | mHasCubeMap = FALSE; | ||
532 | mHasATIVAO = FALSE; | ||
533 | mHasOcclusionQuery = FALSE; | ||
534 | mHasShaderObjects = FALSE; | ||
535 | mHasVertexShader = FALSE; | ||
536 | mHasFragmentShader = FALSE; | ||
537 | #else // LL_MESA_HEADLESS | ||
538 | mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); | ||
539 | mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); | ||
540 | mHasPalettedTextures = glh_init_extension("GL_EXT_paletted_texture"); | ||
541 | mHasNVVertexArrayRange = glh_init_extensions("GL_NV_vertex_array_range"); | ||
542 | mHasNVFence = glh_init_extensions("GL_NV_fence"); | ||
543 | mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); | ||
544 | mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); | ||
545 | glh_init_extensions("GL_ARB_texture_cube_map"); | ||
546 | mHasCubeMap = ExtensionExists("GL_ARB_texture_cube_map", gGLHExts.mSysExts); | ||
547 | mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts); | ||
548 | mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression"); | ||
549 | mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts); | ||
550 | mHasATIVAO = ExtensionExists("GL_ATI_vertex_array_object", gGLHExts.mSysExts); | ||
551 | mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts); | ||
552 | mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); | ||
553 | mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts) | ||
554 | && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); | ||
555 | mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts); | ||
556 | #endif | ||
557 | |||
558 | #if LL_LINUX | ||
559 | // Our extension support for the Linux Client is very young with some | ||
560 | // potential driver gotchas, so offer a semi-secret way to turn it off. | ||
561 | if (getenv("LL_GL_NOEXT")) | ||
562 | { | ||
563 | //mHasMultitexture = FALSE; // NEEDED! | ||
564 | mHasARBEnvCombine = FALSE; | ||
565 | mHasCompressedTextures = FALSE; | ||
566 | mHasVertexBufferObject = FALSE; | ||
567 | mHasMipMapGeneration = FALSE; | ||
568 | mHasPalettedTextures = FALSE; | ||
569 | mHasNVVertexArrayRange = FALSE; | ||
570 | mHasNVFence = FALSE; | ||
571 | mHasSeparateSpecularColor = FALSE; | ||
572 | mHasAnisotropic = FALSE; | ||
573 | mHasCubeMap = FALSE; | ||
574 | mHasATIVAO = FALSE; | ||
575 | mHasOcclusionQuery = FALSE; | ||
576 | mHasShaderObjects = FALSE; | ||
577 | mHasVertexShader = FALSE; | ||
578 | mHasFragmentShader = FALSE; | ||
579 | llwarns << "GL extension support DISABLED via LL_GL_NOEXT" << | ||
580 | llendl; | ||
581 | } | ||
582 | else if (getenv("LL_GL_BASICEXT")) | ||
583 | { | ||
584 | // This switch attempts to turn off all support for exotic | ||
585 | // extensions which I believe correspond to fatal driver | ||
586 | // bug reports. This should be the default until we get a | ||
587 | // proper blacklist/whitelist on Linux. | ||
588 | mHasMipMapGeneration = FALSE; | ||
589 | mHasPalettedTextures = FALSE; | ||
590 | mHasNVVertexArrayRange = FALSE; | ||
591 | mHasNVFence = FALSE; | ||
592 | mHasAnisotropic = FALSE; | ||
593 | mHasATIVAO = FALSE; | ||
594 | mHasOcclusionQuery = FALSE; // source of many ATI system hangs | ||
595 | mHasShaderObjects = FALSE; | ||
596 | mHasVertexShader = FALSE; | ||
597 | mHasFragmentShader = FALSE; | ||
598 | llwarns << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << | ||
599 | llendl; | ||
600 | } | ||
601 | if (getenv("LL_GL_BLACKLIST")) | ||
602 | { | ||
603 | // This lets advanced troubleshooters disable specific | ||
604 | // GL extensions to isolate problems with their hardware. | ||
605 | // SL-28126 | ||
606 | const char *const blacklist = getenv("LL_GL_BLACKLIST"); | ||
607 | llwarns << "GL extension support partially disabled via LL_GL_BLACKLIST: " << blacklist << llendl; | ||
608 | if (strchr(blacklist,'a')) mHasARBEnvCombine = FALSE; | ||
609 | if (strchr(blacklist,'b')) mHasCompressedTextures = FALSE; | ||
610 | if (strchr(blacklist,'c')) mHasVertexBufferObject = FALSE; | ||
611 | if (strchr(blacklist,'d')) mHasMipMapGeneration = FALSE;//S | ||
612 | if (strchr(blacklist,'e')) mHasPalettedTextures = FALSE;//S | ||
613 | if (strchr(blacklist,'f')) mHasNVVertexArrayRange = FALSE;//S | ||
614 | if (strchr(blacklist,'g')) mHasNVFence = FALSE;//S | ||
615 | if (strchr(blacklist,'h')) mHasSeparateSpecularColor = FALSE; | ||
616 | if (strchr(blacklist,'i')) mHasAnisotropic = FALSE;//S | ||
617 | if (strchr(blacklist,'j')) mHasCubeMap = FALSE; | ||
618 | if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S | ||
619 | if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE; | ||
620 | if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S | ||
621 | if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S | ||
622 | if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S | ||
623 | } | ||
624 | #endif // LL_LINUX | ||
625 | |||
626 | #if LL_DARWIN || LL_LINUX | ||
627 | // MBW -- 12/4/2003 -- Using paletted textures causes a bunch of avatar rendering problems on the Mac. | ||
628 | // Not sure if this is due to driver problems or incorrect use of the extension, but I'm disabling it for now. | ||
629 | // Tofu - 2006-10-03 -- Same problem on Linux. | ||
630 | mHasPalettedTextures = false; | ||
631 | #endif | ||
632 | |||
633 | if (!mHasMultitexture) | ||
634 | { | ||
635 | llinfos << "Couldn't initialize multitexturing" << llendl; | ||
636 | } | ||
637 | if (!mHasMipMapGeneration) | ||
638 | { | ||
639 | llinfos << "Couldn't initialize mipmap generation" << llendl; | ||
640 | } | ||
641 | if (!mHasARBEnvCombine) | ||
642 | { | ||
643 | llinfos << "Couldn't initialize GL_ARB_texture_env_combine" << llendl; | ||
644 | } | ||
645 | if (!mHasPalettedTextures) | ||
646 | { | ||
647 | llinfos << "Couldn't initialize GL_EXT_paletted_texture" << llendl; | ||
648 | } | ||
649 | if (!mHasNVVertexArrayRange) | ||
650 | { | ||
651 | llinfos << "Couldn't initialize GL_NV_vertex_array_range" << llendl; | ||
652 | } | ||
653 | if (!mHasNVFence) | ||
654 | { | ||
655 | llinfos << "Couldn't initialize GL_NV_fence" << llendl; | ||
656 | } | ||
657 | if (!mHasSeparateSpecularColor) | ||
658 | { | ||
659 | llinfos << "Couldn't initialize separate specular color" << llendl; | ||
660 | } | ||
661 | if (!mHasAnisotropic) | ||
662 | { | ||
663 | llinfos << "Couldn't initialize anisotropic filtering" << llendl; | ||
664 | } | ||
665 | if (!mHasCompressedTextures) | ||
666 | { | ||
667 | llinfos << "Couldn't initialize GL_ARB_texture_compression" << llendl; | ||
668 | } | ||
669 | if (!mHasOcclusionQuery) | ||
670 | { | ||
671 | llinfos << "Couldn't initialize GL_ARB_occlusion_query" << llendl; | ||
672 | } | ||
673 | if (!mHasShaderObjects) | ||
674 | { | ||
675 | llinfos << "Couldn't initialize GL_ARB_shader_objects" << llendl; | ||
676 | } | ||
677 | if (!mHasVertexShader) | ||
678 | { | ||
679 | llinfos << "Couldn't initialize GL_ARB_vertex_shader" << llendl; | ||
680 | } | ||
681 | if (!mHasFragmentShader) | ||
682 | { | ||
683 | llinfos << "Couldn't initialize GL_ARB_fragment_shader" << llendl; | ||
684 | } | ||
685 | |||
686 | // Disable certain things due to known bugs | ||
687 | if (mIsIntel && mHasMipMapGeneration) | ||
688 | { | ||
689 | llinfos << "Disabling mip-map generation for Intel GPUs" << llendl; | ||
690 | mHasMipMapGeneration = FALSE; | ||
691 | } | ||
692 | if (mIsATI && mHasMipMapGeneration) | ||
693 | { | ||
694 | llinfos << "Disabling mip-map generation for ATI GPUs (performance opt)" << llendl; | ||
695 | mHasMipMapGeneration = FALSE; | ||
696 | } | ||
697 | |||
698 | // Misc | ||
699 | if (mHasNVFence || mHasATIVAO) | ||
700 | { | ||
701 | mHasAnyAGP = TRUE; | ||
702 | } | ||
703 | glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); | ||
704 | glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); | ||
705 | |||
706 | // Apple specific | ||
707 | #if LL_DARWIN | ||
708 | mHasAPPLEVertexArrayRange = glh_init_extensions("GL_APPLE_vertex_array_range"); | ||
709 | if (!mHasAPPLEVertexArrayRange) | ||
710 | { | ||
711 | llinfos << "Couldn't initialize GL_APPLE_vertex_array_range" << llendl; | ||
712 | } | ||
713 | |||
714 | mHasAPPLEFence = glh_init_extensions("GL_APPLE_fence"); | ||
715 | if (!mHasAPPLEFence) | ||
716 | { | ||
717 | llinfos << "Couldn't initialize GL_APPLE_fence" << llendl; | ||
718 | } | ||
719 | |||
720 | mHasAPPLEVAO = glh_init_extensions("GL_APPLE_vertex_array_object"); | ||
721 | if (mHasAPPLEVAO) | ||
722 | { | ||
723 | llinfos << "Has GL_APPLE_vertex_array_object!" << llendl; | ||
724 | } | ||
725 | |||
726 | if(mHasAPPLEFence) | ||
727 | { | ||
728 | mHasAnyAGP = TRUE; | ||
729 | } | ||
730 | #endif // LL_DARWIN | ||
731 | |||
732 | #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS | ||
733 | llinfos << "GL Probe: Getting symbols" << llendl; | ||
734 | if (mHasVertexBufferObject) | ||
735 | { | ||
736 | glBindBufferARB = (PFNGLBINDBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindBufferARB"); | ||
737 | glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteBuffersARB"); | ||
738 | glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenBuffersARB"); | ||
739 | glIsBufferARB = (PFNGLISBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsBufferARB"); | ||
740 | glBufferDataARB = (PFNGLBUFFERDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferDataARB"); | ||
741 | glBufferSubDataARB = (PFNGLBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBufferSubDataARB"); | ||
742 | glGetBufferSubDataARB = (PFNGLGETBUFFERSUBDATAARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferSubDataARB"); | ||
743 | glMapBufferARB = (PFNGLMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMapBufferARB"); | ||
744 | glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glUnmapBufferARB"); | ||
745 | glGetBufferParameterivARB = (PFNGLGETBUFFERPARAMETERIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferParameterivARB"); | ||
746 | glGetBufferPointervARB = (PFNGLGETBUFFERPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetBufferPointervARB"); | ||
747 | } | ||
748 | if (mHasATIVAO) | ||
749 | { | ||
750 | // Initialize the extension. | ||
751 | llinfos << "Has ATI_vertex_array_object!" << llendl; | ||
752 | glNewObjectBufferATI = (PFNGLNEWOBJECTBUFFERATIPROC)GLH_EXT_GET_PROC_ADDRESS("glNewObjectBufferATI"); | ||
753 | glIsObjectBufferATI = (PFNGLISOBJECTBUFFERATIPROC)GLH_EXT_GET_PROC_ADDRESS("glIsObjectBufferATI"); | ||
754 | glUpdateObjectBufferATI = (PFNGLUPDATEOBJECTBUFFERATIPROC)GLH_EXT_GET_PROC_ADDRESS("glUpdateObjectBufferATI"); | ||
755 | glGetObjectBufferfvATI = (PFNGLGETOBJECTBUFFERFVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetObjectBufferfvATI"); | ||
756 | glGetObjectBufferivATI = (PFNGLGETOBJECTBUFFERIVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetObjectBufferivATI"); | ||
757 | glFreeObjectBufferATI = (PFNGLFREEOBJECTBUFFERATIPROC)GLH_EXT_GET_PROC_ADDRESS("glFreeObjectBufferATI"); | ||
758 | glArrayObjectATI = (PFNGLARRAYOBJECTATIPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayObjectATI"); | ||
759 | glVertexAttribArrayObjectATI = (PFNGLVERTEXATTRIBARRAYOBJECTATIPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribArrayObjectATI"); | ||
760 | glGetArrayObjectfvATI = (PFNGLGETARRAYOBJECTFVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetArrayObjectfvATI"); | ||
761 | glGetArrayObjectivATI = (PFNGLGETARRAYOBJECTIVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetArrayObjectivATI"); | ||
762 | glVariantObjectArrayATI = (PFNGLVARIANTARRAYOBJECTATIPROC)GLH_EXT_GET_PROC_ADDRESS("glVariantObjectArrayATI"); | ||
763 | glGetVariantArrayObjectfvATI = (PFNGLGETVARIANTARRAYOBJECTFVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVariantArrayObjectfvATI"); | ||
764 | glGetVariantArrayObjectivATI = (PFNGLGETVARIANTARRAYOBJECTIVATIPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVariantArrayObjectivATI"); | ||
765 | } | ||
766 | #if !LL_LINUX | ||
767 | // This is expected to be a static symbol on Linux GL implementations | ||
768 | glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); | ||
769 | if (!glDrawRangeElements) | ||
770 | { | ||
771 | mGLMaxVertexRange = 0; | ||
772 | mGLMaxIndexRange = 0; | ||
773 | } | ||
774 | #endif // !LL_LINUX | ||
775 | #if LL_LINUX | ||
776 | // On Linux we need to get glColorTableEXT dynamically. | ||
777 | if (mHasPalettedTextures) | ||
778 | { | ||
779 | glColorTableEXT = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT"); | ||
780 | } | ||
781 | #endif // LL_LINUX | ||
782 | if (mHasOcclusionQuery) | ||
783 | { | ||
784 | glGenQueriesARB = (PFNGLGENQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenQueriesARB"); | ||
785 | glDeleteQueriesARB = (PFNGLDELETEQUERIESARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteQueriesARB"); | ||
786 | glIsQueryARB = (PFNGLISQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsQueryARB"); | ||
787 | glBeginQueryARB = (PFNGLBEGINQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBeginQueryARB"); | ||
788 | glEndQueryARB = (PFNGLENDQUERYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEndQueryARB"); | ||
789 | glGetQueryivARB = (PFNGLGETQUERYIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryivARB"); | ||
790 | glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB"); | ||
791 | glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB"); | ||
792 | } | ||
793 | if (mHasShaderObjects) | ||
794 | { | ||
795 | glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB"); | ||
796 | glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB"); | ||
797 | glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB"); | ||
798 | glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB"); | ||
799 | glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB"); | ||
800 | glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB"); | ||
801 | glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB"); | ||
802 | glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB"); | ||
803 | glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB"); | ||
804 | glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB"); | ||
805 | glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB"); | ||
806 | glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB"); | ||
807 | glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB"); | ||
808 | glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB"); | ||
809 | glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB"); | ||
810 | glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB"); | ||
811 | glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB"); | ||
812 | glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB"); | ||
813 | glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB"); | ||
814 | glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB"); | ||
815 | glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB"); | ||
816 | glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB"); | ||
817 | glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB"); | ||
818 | glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB"); | ||
819 | glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB"); | ||
820 | glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB"); | ||
821 | glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); | ||
822 | glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); | ||
823 | glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); | ||
824 | glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); | ||
825 | glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); | ||
826 | glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); | ||
827 | glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB"); | ||
828 | glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB"); | ||
829 | glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB"); | ||
830 | glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB"); | ||
831 | glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB"); | ||
832 | glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB"); | ||
833 | glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB"); | ||
834 | } | ||
835 | if (mHasVertexShader) | ||
836 | { | ||
837 | glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB"); | ||
838 | glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB"); | ||
839 | glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB"); | ||
840 | glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); | ||
841 | glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); | ||
842 | glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); | ||
843 | glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); | ||
844 | glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); | ||
845 | glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); | ||
846 | glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); | ||
847 | glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); | ||
848 | glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); | ||
849 | glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); | ||
850 | glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); | ||
851 | glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); | ||
852 | glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); | ||
853 | glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); | ||
854 | glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); | ||
855 | glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); | ||
856 | glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); | ||
857 | glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); | ||
858 | glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB"); | ||
859 | glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB"); | ||
860 | glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB"); | ||
861 | glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB"); | ||
862 | glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB"); | ||
863 | glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB"); | ||
864 | glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB"); | ||
865 | glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); | ||
866 | glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); | ||
867 | glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); | ||
868 | glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); | ||
869 | glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); | ||
870 | glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); | ||
871 | glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); | ||
872 | glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); | ||
873 | glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); | ||
874 | glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); | ||
875 | glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); | ||
876 | glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); | ||
877 | glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); | ||
878 | glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); | ||
879 | glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); | ||
880 | glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); | ||
881 | glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); | ||
882 | glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); | ||
883 | glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); | ||
884 | glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); | ||
885 | glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); | ||
886 | glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); | ||
887 | glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); | ||
888 | glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); | ||
889 | glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); | ||
890 | glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); | ||
891 | glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); | ||
892 | glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); | ||
893 | glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); | ||
894 | glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); | ||
895 | glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); | ||
896 | glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); | ||
897 | glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); | ||
898 | glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); | ||
899 | glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); | ||
900 | glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB"); | ||
901 | glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); | ||
902 | } | ||
903 | llinfos << "GL Probe: Got symbols" << llendl; | ||
904 | #endif | ||
905 | |||
906 | mInited = TRUE; | ||
907 | } | ||
908 | |||
909 | void rotate_quat(LLQuaternion& rotation) | ||
910 | { | ||
911 | F32 angle_radians, x, y, z; | ||
912 | rotation.getAngleAxis(&angle_radians, &x, &y, &z); | ||
913 | glRotatef(angle_radians * RAD_TO_DEG, x, y, z); | ||
914 | } | ||
915 | |||
916 | void flush_glerror() | ||
917 | { | ||
918 | glGetError(); | ||
919 | } | ||
920 | |||
921 | void assert_glerror() | ||
922 | { | ||
923 | if (gNoRender) | ||
924 | { | ||
925 | return; | ||
926 | } | ||
927 | if (!gGLManager.mInited) | ||
928 | { | ||
929 | llerrs << "GL not initialized" << llendl; | ||
930 | } | ||
931 | // Create or update texture to be used with this data | ||
932 | GLenum error; | ||
933 | error = glGetError(); | ||
934 | if (error) | ||
935 | { | ||
936 | #ifndef LL_LINUX // *FIX: ! This should be an error for linux as well. | ||
937 | llerrs << "GL Error:" << gluErrorString(error) << llendl; | ||
938 | #endif | ||
939 | } | ||
940 | } | ||
941 | |||
942 | void clear_glerror() | ||
943 | { | ||
944 | // Create or update texture to be used with this data | ||
945 | GLenum error; | ||
946 | error = glGetError(); | ||
947 | } | ||
948 | |||
949 | //============================================================================ | ||
950 | |||
951 | // | ||
952 | // LLGLState | ||
953 | // | ||
954 | |||
955 | // Static members | ||
956 | std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap; | ||
957 | |||
958 | GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default | ||
959 | GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default | ||
960 | GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default | ||
961 | |||
962 | //static | ||
963 | void LLGLState::initClass() | ||
964 | { | ||
965 | sStateMap[GL_DITHER] = GL_TRUE; | ||
966 | } | ||
967 | |||
968 | //static | ||
969 | void LLGLState::restoreGL() | ||
970 | { | ||
971 | sStateMap.clear(); | ||
972 | initClass(); | ||
973 | } | ||
974 | |||
975 | void LLGLState::dumpStates() | ||
976 | { | ||
977 | llinfos << "GL States:" << llendl; | ||
978 | for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); | ||
979 | iter != sStateMap.end(); ++iter) | ||
980 | { | ||
981 | llinfos << llformat(" 0x%04x : %s",(S32)iter->first,iter->second?"TRUE":"FALSE") << llendl; | ||
982 | } | ||
983 | } | ||
984 | |||
985 | void LLGLState::checkStates() | ||
986 | { | ||
987 | stop_glerror(); | ||
988 | |||
989 | GLint activeTexture; | ||
990 | glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture); | ||
991 | |||
992 | if (activeTexture != GL_TEXTURE0_ARB) | ||
993 | { | ||
994 | LL_GL_ERRS << "Texture channel corrupted. " << llendl; | ||
995 | } | ||
996 | |||
997 | GLint src; | ||
998 | GLint dst; | ||
999 | glGetIntegerv(GL_BLEND_SRC, &src); | ||
1000 | glGetIntegerv(GL_BLEND_DST, &dst); | ||
1001 | |||
1002 | if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) | ||
1003 | { | ||
1004 | LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << llendl; | ||
1005 | } | ||
1006 | |||
1007 | for (std::map<LLGLenum, LLGLboolean>::iterator iter = sStateMap.begin(); | ||
1008 | iter != sStateMap.end(); ++iter) | ||
1009 | { | ||
1010 | LLGLenum state = iter->first; | ||
1011 | LLGLboolean cur_state = iter->second; | ||
1012 | LLGLboolean gl_state = glIsEnabled(state); | ||
1013 | if(cur_state != gl_state) | ||
1014 | { | ||
1015 | dumpStates(); | ||
1016 | LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << llendl; | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | stop_glerror(); | ||
1021 | } | ||
1022 | |||
1023 | void LLGLState::checkTextureChannels() | ||
1024 | { | ||
1025 | GLint activeTexture; | ||
1026 | glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture); | ||
1027 | |||
1028 | BOOL error = FALSE; | ||
1029 | |||
1030 | if (activeTexture != GL_TEXTURE0_ARB) | ||
1031 | { | ||
1032 | error = TRUE; | ||
1033 | llwarns << "Active texture channel corrupted. " << llendl; | ||
1034 | } | ||
1035 | |||
1036 | GLint maxTextureUnits; | ||
1037 | glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); | ||
1038 | |||
1039 | static const char* label[] = | ||
1040 | { | ||
1041 | "GL_TEXTURE_2D", | ||
1042 | "GL_TEXTURE_COORD_ARRAY", | ||
1043 | "GL_TEXTURE_1D", | ||
1044 | "GL_TEXTURE_CUBE_MAP_ARB", | ||
1045 | "GL_TEXTURE_GEN_S", | ||
1046 | "GL_TEXTURE_GEN_T", | ||
1047 | "GL_TEXTURE_GEN_Q", | ||
1048 | "GL_TEXTURE_GEN_R" | ||
1049 | }; | ||
1050 | |||
1051 | static GLint value[] = | ||
1052 | { | ||
1053 | GL_TEXTURE_2D, | ||
1054 | GL_TEXTURE_COORD_ARRAY, | ||
1055 | GL_TEXTURE_1D, | ||
1056 | GL_TEXTURE_CUBE_MAP_ARB, | ||
1057 | GL_TEXTURE_GEN_S, | ||
1058 | GL_TEXTURE_GEN_T, | ||
1059 | GL_TEXTURE_GEN_Q, | ||
1060 | GL_TEXTURE_GEN_R | ||
1061 | }; | ||
1062 | |||
1063 | GLint stackDepth = 0; | ||
1064 | LLMatrix4 identity; | ||
1065 | LLMatrix4 matrix; | ||
1066 | |||
1067 | for (GLint i = 0; i < maxTextureUnits; i++) | ||
1068 | { | ||
1069 | glActiveTextureARB(GL_TEXTURE0_ARB+i); | ||
1070 | glClientActiveTextureARB(GL_TEXTURE0_ARB+i); | ||
1071 | |||
1072 | glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth); | ||
1073 | |||
1074 | if (stackDepth != 1) | ||
1075 | { | ||
1076 | error = TRUE; | ||
1077 | llwarns << "Texture matrix stack corrupted." << llendl; | ||
1078 | } | ||
1079 | |||
1080 | glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); | ||
1081 | |||
1082 | if (matrix != identity) | ||
1083 | { | ||
1084 | error = TRUE; | ||
1085 | llwarns << "Texture matrix in channel " << i << " corrupt." << llendl; | ||
1086 | } | ||
1087 | |||
1088 | for (S32 j = (i == 0 ? 2 : 0); j < 8; j++) | ||
1089 | { | ||
1090 | if (glIsEnabled(value[j])) | ||
1091 | { | ||
1092 | error = TRUE; | ||
1093 | llwarns << "Texture channel " << i << " still has " << label[j] << " enabled." << llendl; | ||
1094 | } | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | glActiveTextureARB(GL_TEXTURE0_ARB); | ||
1099 | glClientActiveTextureARB(GL_TEXTURE0_ARB); | ||
1100 | |||
1101 | if (error) | ||
1102 | { | ||
1103 | LL_GL_ERRS << "GL texture state corruption detected." << llendl; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | void LLGLState::checkClientArrays() | ||
1108 | { | ||
1109 | BOOL error = FALSE; | ||
1110 | static const char* label[] = | ||
1111 | { | ||
1112 | //"GL_INDEX_ARRAY", | ||
1113 | "GL_NORMAL_ARRAY", | ||
1114 | //"GL_VERTEX_ARRAY", | ||
1115 | "GL_COLOR_ARRAY", | ||
1116 | "GL_TEXTURE_COORD_ARRAY" | ||
1117 | }; | ||
1118 | |||
1119 | static GLint value[] = | ||
1120 | { | ||
1121 | //GL_INDEX_ARRAY, | ||
1122 | GL_NORMAL_ARRAY, | ||
1123 | //GL_VERTEX_ARRAY, | ||
1124 | GL_COLOR_ARRAY, | ||
1125 | GL_TEXTURE_COORD_ARRAY | ||
1126 | }; | ||
1127 | |||
1128 | for (S32 j = 0; j < 3; j++) | ||
1129 | { | ||
1130 | if (glIsEnabled(value[j])) | ||
1131 | { | ||
1132 | error = TRUE; | ||
1133 | llwarns << "GL still has " << label[j] << " enabled." << llendl; | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | if (error) | ||
1138 | { | ||
1139 | LL_GL_ERRS << "GL client array corruption detected." << llendl; | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | //============================================================================ | ||
1144 | |||
1145 | LLGLState::LLGLState(LLGLenum state, S32 enabled) | ||
1146 | { | ||
1147 | stop_glerror(); | ||
1148 | mState = state; | ||
1149 | if (state) | ||
1150 | { | ||
1151 | mWasEnabled = sStateMap[state]; | ||
1152 | llassert(mWasEnabled == glIsEnabled(state)); | ||
1153 | setEnabled(enabled); | ||
1154 | stop_glerror(); | ||
1155 | } | ||
1156 | } | ||
1157 | |||
1158 | void LLGLState::setEnabled(S32 enabled) | ||
1159 | { | ||
1160 | if (!mState) | ||
1161 | { | ||
1162 | return; | ||
1163 | } | ||
1164 | if (enabled == CURRENT_STATE) | ||
1165 | { | ||
1166 | enabled = sStateMap[mState] == GL_TRUE ? TRUE : FALSE; | ||
1167 | } | ||
1168 | else if (enabled == TRUE && sStateMap[mState] != GL_TRUE) | ||
1169 | { | ||
1170 | glEnable(mState); | ||
1171 | sStateMap[mState] = GL_TRUE; | ||
1172 | } | ||
1173 | else if (enabled == FALSE && sStateMap[mState] != GL_FALSE) | ||
1174 | { | ||
1175 | glDisable(mState); | ||
1176 | sStateMap[mState] = GL_FALSE; | ||
1177 | } | ||
1178 | mIsEnabled = enabled; | ||
1179 | } | ||
1180 | |||
1181 | LLGLState::~LLGLState() | ||
1182 | { | ||
1183 | stop_glerror(); | ||
1184 | if (mState) | ||
1185 | { | ||
1186 | #if LL_DEBUG | ||
1187 | LLGLboolean cur_state = sStateMap[mState]; | ||
1188 | llassert(cur_state == glIsEnabled(mState)); | ||
1189 | #endif | ||
1190 | if (mIsEnabled != mWasEnabled) | ||
1191 | { | ||
1192 | if (mWasEnabled) | ||
1193 | { | ||
1194 | glEnable(mState); | ||
1195 | sStateMap[mState] = GL_TRUE; | ||
1196 | } | ||
1197 | else | ||
1198 | { | ||
1199 | glDisable(mState); | ||
1200 | sStateMap[mState] = GL_FALSE; | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | stop_glerror(); | ||
1205 | } | ||
1206 | |||
1207 | //============================================================================ | ||
1208 | |||
1209 | void LLGLManager::initGLStates() | ||
1210 | { | ||
1211 | //gl states moved to classes in llglstates.h | ||
1212 | LLGLState::initClass(); | ||
1213 | } | ||
1214 | |||
1215 | //============================================================================ | ||
1216 | |||
1217 | void enable_vertex_weighting(const S32 index) | ||
1218 | { | ||
1219 | #if GL_ARB_vertex_program | ||
1220 | if (index > 0) glEnableVertexAttribArrayARB(index); // vertex weights | ||
1221 | #endif | ||
1222 | } | ||
1223 | |||
1224 | void disable_vertex_weighting(const S32 index) | ||
1225 | { | ||
1226 | #if GL_ARB_vertex_program | ||
1227 | if (index > 0) glDisableVertexAttribArrayARB(index); // vertex weights | ||
1228 | #endif | ||
1229 | } | ||
1230 | |||
1231 | void enable_binormals(const S32 index) | ||
1232 | { | ||
1233 | #if GL_ARB_vertex_program | ||
1234 | if (index > 0) | ||
1235 | { | ||
1236 | glEnableVertexAttribArrayARB(index); // binormals | ||
1237 | } | ||
1238 | #endif | ||
1239 | } | ||
1240 | |||
1241 | void disable_binormals(const S32 index) | ||
1242 | { | ||
1243 | #if GL_ARB_vertex_program | ||
1244 | if (index > 0) | ||
1245 | { | ||
1246 | glDisableVertexAttribArrayARB(index); // binormals | ||
1247 | } | ||
1248 | #endif | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | void enable_cloth_weights(const S32 index) | ||
1253 | { | ||
1254 | #if GL_ARB_vertex_program | ||
1255 | if (index > 0) glEnableVertexAttribArrayARB(index); | ||
1256 | #endif | ||
1257 | } | ||
1258 | |||
1259 | void disable_cloth_weights(const S32 index) | ||
1260 | { | ||
1261 | #if GL_ARB_vertex_program | ||
1262 | if (index > 0) glDisableVertexAttribArrayARB(index); | ||
1263 | #endif | ||
1264 | } | ||
1265 | |||
1266 | void set_vertex_weights(const S32 index, const F32 *weights) | ||
1267 | { | ||
1268 | #if GL_ARB_vertex_program | ||
1269 | if (index > 0) glVertexAttribPointerARB(index, 1, GL_FLOAT, FALSE, 0, weights); | ||
1270 | stop_glerror(); | ||
1271 | #endif | ||
1272 | } | ||
1273 | |||
1274 | void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights) | ||
1275 | { | ||
1276 | #if GL_ARB_vertex_program | ||
1277 | if (index > 0) glVertexAttribPointerARB(index, 4, GL_FLOAT, TRUE, stride, weights); | ||
1278 | stop_glerror(); | ||
1279 | #endif | ||
1280 | } | ||
1281 | |||
1282 | void set_binormals(const S32 index, const U32 stride,const LLVector3 *binormals) | ||
1283 | { | ||
1284 | #if GL_ARB_vertex_program | ||
1285 | if (index > 0) glVertexAttribPointerARB(index, 3, GL_FLOAT, FALSE, stride, binormals); | ||
1286 | stop_glerror(); | ||
1287 | #endif | ||
1288 | } | ||
1289 | |||
1290 | |||
1291 | void set_palette(U8 *palette_data) | ||
1292 | { | ||
1293 | if (gGLManager.mHasPalettedTextures) | ||
1294 | { | ||
1295 | glColorTableEXT(GL_TEXTURE_2D, GL_RGBA8, 256, GL_RGBA, GL_UNSIGNED_BYTE, palette_data); | ||
1296 | } | ||
1297 | } | ||
1298 | |||
1299 | |||
1300 | void parse_gl_version( S32* major, S32* minor, S32* release, LLString* vendor_specific ) | ||
1301 | { | ||
1302 | // GL_VERSION returns a null-terminated string with the format: | ||
1303 | // <major>.<minor>[.<release>] [<vendor specific>] | ||
1304 | |||
1305 | const char* version = (const char*) glGetString(GL_VERSION); | ||
1306 | *major = 0; | ||
1307 | *minor = 0; | ||
1308 | *release = 0; | ||
1309 | vendor_specific->assign(""); | ||
1310 | |||
1311 | if( !version ) | ||
1312 | { | ||
1313 | return; | ||
1314 | } | ||
1315 | |||
1316 | LLString ver_copy( version ); | ||
1317 | S32 len = (S32)strlen( version ); | ||
1318 | S32 i = 0; | ||
1319 | S32 start; | ||
1320 | // Find the major version | ||
1321 | start = i; | ||
1322 | for( ; i < len; i++ ) | ||
1323 | { | ||
1324 | if( '.' == version[i] ) | ||
1325 | { | ||
1326 | break; | ||
1327 | } | ||
1328 | } | ||
1329 | LLString major_str = ver_copy.substr(start,i-start); | ||
1330 | LLString::convertToS32(major_str, *major); | ||
1331 | |||
1332 | if( '.' == version[i] ) | ||
1333 | { | ||
1334 | i++; | ||
1335 | } | ||
1336 | |||
1337 | // Find the minor version | ||
1338 | start = i; | ||
1339 | for( ; i < len; i++ ) | ||
1340 | { | ||
1341 | if( ('.' == version[i]) || isspace(version[i]) ) | ||
1342 | { | ||
1343 | break; | ||
1344 | } | ||
1345 | } | ||
1346 | LLString minor_str = ver_copy.substr(start,i-start); | ||
1347 | LLString::convertToS32(minor_str, *minor); | ||
1348 | |||
1349 | // Find the release number (optional) | ||
1350 | if( '.' == version[i] ) | ||
1351 | { | ||
1352 | i++; | ||
1353 | |||
1354 | start = i; | ||
1355 | for( ; i < len; i++ ) | ||
1356 | { | ||
1357 | if( isspace(version[i]) ) | ||
1358 | { | ||
1359 | break; | ||
1360 | } | ||
1361 | } | ||
1362 | |||
1363 | LLString release_str = ver_copy.substr(start,i-start); | ||
1364 | LLString::convertToS32(release_str, *release); | ||
1365 | } | ||
1366 | |||
1367 | // Skip over any white space | ||
1368 | while( version[i] && isspace( version[i] ) ) | ||
1369 | { | ||
1370 | i++; | ||
1371 | } | ||
1372 | |||
1373 | // Copy the vendor-specific string (optional) | ||
1374 | if( version[i] ) | ||
1375 | { | ||
1376 | vendor_specific->assign( version + i ); | ||
1377 | } | ||
1378 | } | ||
diff --git a/linden/indra/llwindow/llgl.h b/linden/indra/llwindow/llgl.h new file mode 100644 index 0000000..1c93b63 --- /dev/null +++ b/linden/indra/llwindow/llgl.h | |||
@@ -0,0 +1,272 @@ | |||
1 | /** | ||
2 | * @file llgl.h | ||
3 | * @brief LLGL definition | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLGL_H | ||
29 | #define LL_LLGL_H | ||
30 | |||
31 | // This file contains various stuff for handling gl extensions and other gl related stuff. | ||
32 | |||
33 | #include <string> | ||
34 | #include <map> | ||
35 | |||
36 | #include "llerror.h" | ||
37 | #include "v4color.h" | ||
38 | #include "llstring.h" | ||
39 | #include "stdtypes.h" | ||
40 | #include "v4math.h" | ||
41 | #include "llgltypes.h" | ||
42 | |||
43 | #define LL_GL_ERRS llerrs | ||
44 | |||
45 | // Manage GL extensions... | ||
46 | class LLGLManager | ||
47 | { | ||
48 | public: | ||
49 | LLGLManager(); | ||
50 | |||
51 | bool initGL(); | ||
52 | void shutdownGL(); | ||
53 | |||
54 | void initWGL(); // Initializes stupid WGL extensions | ||
55 | |||
56 | LLString getRawGLString(); // For sending to simulator | ||
57 | |||
58 | BOOL mInited; | ||
59 | BOOL mIsDisabled; | ||
60 | |||
61 | // Extensions used by everyone | ||
62 | BOOL mHasMultitexture; | ||
63 | S32 mNumTextureUnits; | ||
64 | BOOL mHasMipMapGeneration; | ||
65 | BOOL mHasAnyAGP; | ||
66 | BOOL mHasPalettedTextures; | ||
67 | BOOL mHasCompressedTextures; | ||
68 | |||
69 | // ARB Extensions | ||
70 | BOOL mHasVertexBufferObject; | ||
71 | BOOL mHasPBuffer; | ||
72 | BOOL mHasShaderObjects; | ||
73 | BOOL mHasVertexShader; | ||
74 | BOOL mHasFragmentShader; | ||
75 | BOOL mHasOcclusionQuery; | ||
76 | |||
77 | // nVidia extensions. | ||
78 | BOOL mHasAnisotropic; | ||
79 | BOOL mHasNVVertexArrayRange; | ||
80 | BOOL mHasNVFence; | ||
81 | BOOL mHasARBEnvCombine; | ||
82 | |||
83 | // ATI extensions. | ||
84 | BOOL mHasATIVAO; | ||
85 | BOOL mIsRadeon8500; // Radeon 8500/9000 | ||
86 | BOOL mIsRadeon9700; | ||
87 | BOOL mIsMobilityRadeon9000; | ||
88 | BOOL mIsGF2or4MX; | ||
89 | BOOL mIsGF3; | ||
90 | BOOL mIsGFFX; | ||
91 | BOOL mIsATI; | ||
92 | BOOL mATIOffsetVerticalLines; | ||
93 | BOOL mIsNVIDIA; | ||
94 | BOOL mIsIntel; | ||
95 | BOOL mHasCubeMap; | ||
96 | |||
97 | #if LL_WINDOWS | ||
98 | BOOL mHasWGLARBPixelFormat; | ||
99 | #endif // LL_WINDOWS | ||
100 | |||
101 | #if LL_DARWIN | ||
102 | // Apple extensions. | ||
103 | BOOL mHasAPPLEVertexArrayRange; | ||
104 | BOOL mHasAPPLEFence; | ||
105 | BOOL mHasAPPLEVAO; | ||
106 | #endif | ||
107 | |||
108 | // Misc exitensions | ||
109 | BOOL mHasSeparateSpecularColor; | ||
110 | |||
111 | S32 mDriverVersionMajor; | ||
112 | S32 mDriverVersionMinor; | ||
113 | S32 mDriverVersionRelease; | ||
114 | F32 mGLVersion; // e.g = 1.4 | ||
115 | LLString mDriverVersionVendorString; | ||
116 | |||
117 | S32 mVRAM; // VRAM in MB | ||
118 | S32 mGLMaxVertexRange; | ||
119 | S32 mGLMaxIndexRange; | ||
120 | BOOL mSoftwareBlendSSE; | ||
121 | |||
122 | void getPixelFormat(); // Get the best pixel format | ||
123 | |||
124 | LLString getGLInfoString(); | ||
125 | |||
126 | // In ALL CAPS | ||
127 | LLString mGLVendor; | ||
128 | |||
129 | // In ALL CAPS | ||
130 | LLString mGLRenderer; | ||
131 | |||
132 | private: | ||
133 | void initExtensions(); | ||
134 | void initGLStates(); | ||
135 | void initGLImages(); | ||
136 | }; | ||
137 | |||
138 | extern LLGLManager gGLManager; | ||
139 | |||
140 | class LLQuaternion; | ||
141 | class LLMatrix4; | ||
142 | |||
143 | void rotate_quat(LLQuaternion& rotation); | ||
144 | |||
145 | void flush_glerror(); // Flush GL errors when we know we're handling them correctly. | ||
146 | |||
147 | void assert_glerror(); | ||
148 | |||
149 | void clear_glerror(); | ||
150 | |||
151 | #if LL_DEBUG | ||
152 | # define stop_glerror() assert_glerror() | ||
153 | # define llglassertok() assert_glerror() | ||
154 | #else | ||
155 | # define stop_glerror() | ||
156 | # define llglassertok() | ||
157 | #endif | ||
158 | |||
159 | #define llglassertok_always() assert_glerror() | ||
160 | |||
161 | //////////////////////// | ||
162 | // | ||
163 | // Note: U32's are GLEnum's... | ||
164 | // | ||
165 | |||
166 | // This is a class for GL state management | ||
167 | |||
168 | /* | ||
169 | GL STATE MANAGEMENT DESCRIPTION | ||
170 | |||
171 | LLGLState and its two subclasses, LLGLEnable and LLGLDisable, manage the current | ||
172 | enable/disable states of the GL to prevent redundant setting of state within a | ||
173 | render path or the accidental corruption of what state the next path expects. | ||
174 | |||
175 | Essentially, wherever you would call glEnable set a state and then | ||
176 | subsequently reset it by calling glDisable (or vice versa), make an instance of | ||
177 | LLGLEnable with the state you want to set, and assume it will be restored to its | ||
178 | original state when that instance of LLGLEnable is destroyed. It is good practice | ||
179 | to exploit stack frame controls for optimal setting/unsetting and readability of | ||
180 | code. In llglstates.h, there are a collection of helper classes that define groups | ||
181 | of enables/disables that can cause multiple states to be set with the creation of | ||
182 | one instance. | ||
183 | |||
184 | Sample usage: | ||
185 | |||
186 | //disable lighting for rendering hud objects | ||
187 | //INCORRECT USAGE | ||
188 | LLGLEnable lighting(GL_LIGHTING); | ||
189 | renderHUD(); | ||
190 | LLGLDisable lighting(GL_LIGHTING); | ||
191 | |||
192 | //CORRECT USAGE | ||
193 | { | ||
194 | LLGLEnable lighting(GL_LIGHTING); | ||
195 | renderHUD(); | ||
196 | } | ||
197 | |||
198 | If a state is to be set on a conditional, the following mechanism | ||
199 | is useful: | ||
200 | |||
201 | { | ||
202 | LLGLEnable lighting(light_hud ? GL_LIGHTING : 0); | ||
203 | renderHUD(); | ||
204 | } | ||
205 | |||
206 | A LLGLState initialized with a parameter of 0 does nothing. | ||
207 | |||
208 | LLGLState works by maintaining a map of the current GL states, and ignoring redundant | ||
209 | enables/disables. If a redundant call is attempted, it becomes a noop, otherwise, | ||
210 | it is set in the constructor and reset in the destructor. | ||
211 | |||
212 | For debugging GL state corruption, running with debug enabled will trigger asserts | ||
213 | if the existing GL state does not match the expected GL state. | ||
214 | |||
215 | */ | ||
216 | class LLGLState | ||
217 | { | ||
218 | public: | ||
219 | static void initClass(); | ||
220 | static void restoreGL(); | ||
221 | |||
222 | static void dumpStates(); | ||
223 | static void checkStates(); | ||
224 | static void checkTextureChannels(); | ||
225 | static void checkClientArrays(); | ||
226 | |||
227 | protected: | ||
228 | static std::map<LLGLenum, LLGLboolean> sStateMap; | ||
229 | |||
230 | public: | ||
231 | enum { CURRENT_STATE = -2 }; | ||
232 | LLGLState(LLGLenum state, S32 enabled = CURRENT_STATE); | ||
233 | ~LLGLState(); | ||
234 | void setEnabled(S32 enabled); | ||
235 | void enable() { setEnabled(TRUE); } | ||
236 | void disable() { setEnabled(FALSE); } | ||
237 | protected: | ||
238 | LLGLenum mState; | ||
239 | BOOL mWasEnabled; | ||
240 | BOOL mIsEnabled; | ||
241 | }; | ||
242 | |||
243 | class LLGLEnable : public LLGLState | ||
244 | { | ||
245 | public: | ||
246 | LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {} | ||
247 | }; | ||
248 | |||
249 | class LLGLDisable : public LLGLState | ||
250 | { | ||
251 | public: | ||
252 | LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {} | ||
253 | }; | ||
254 | |||
255 | #include "llglstates.h" | ||
256 | |||
257 | void init_glstates(); | ||
258 | void enable_vertex_weighting(const S32 index); | ||
259 | void disable_vertex_weighting(const S32 index); | ||
260 | void enable_binormals(const S32 index); | ||
261 | void disable_binormals(const S32 index); | ||
262 | void enable_cloth_weights(const S32 index); | ||
263 | void disable_cloth_weights(const S32 index); | ||
264 | void set_vertex_weights(const S32 index, const F32 *weights); | ||
265 | void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights); | ||
266 | void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals); | ||
267 | void set_palette(U8* palette_data); | ||
268 | void parse_gl_version( S32* major, S32* minor, S32* release, LLString* vendor_specific ); | ||
269 | |||
270 | extern BOOL gClothRipple; | ||
271 | extern BOOL gNoRender; | ||
272 | #endif // LL_LLGL_H | ||
diff --git a/linden/indra/llwindow/llglheaders.h b/linden/indra/llwindow/llglheaders.h new file mode 100644 index 0000000..e67b6c7 --- /dev/null +++ b/linden/indra/llwindow/llglheaders.h | |||
@@ -0,0 +1,486 @@ | |||
1 | /** | ||
2 | * @file llglheaders.h | ||
3 | * @brief LLGL definitions | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLGLHEADERS_H | ||
29 | #define LL_LLGLHEADERS_H | ||
30 | |||
31 | #if LL_LINUX | ||
32 | # ifndef LL_MESA | ||
33 | # define LL_MESA 1 // force MESA | ||
34 | # endif | ||
35 | # ifndef LL_MESA_HEADLESS | ||
36 | # define LL_MESA_HEADLESS 1 // force MESA HEADLESS | ||
37 | # endif | ||
38 | #endif | ||
39 | |||
40 | #if LL_MESA | ||
41 | //---------------------------------------------------------------------------- | ||
42 | // MESA headers | ||
43 | // quotes so we get libraries/.../GL/ version | ||
44 | #define GL_GLEXT_PROTOTYPES | ||
45 | #include "GL/gl.h" | ||
46 | #include "GL/glext.h" | ||
47 | #include "GL/glu.h" | ||
48 | |||
49 | #elif LL_LINUX | ||
50 | //---------------------------------------------------------------------------- | ||
51 | // Linux, MESA headers, but not necessarily assuming MESA runtime. | ||
52 | // quotes so we get libraries/.../GL/ version | ||
53 | #include "GL/gl.h" | ||
54 | #include "GL/glext.h" | ||
55 | #include "GL/glu.h" | ||
56 | |||
57 | // GL_ARB_vertex_buffer_object | ||
58 | extern PFNGLBINDBUFFERARBPROC glBindBufferARB; | ||
59 | extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; | ||
60 | extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; | ||
61 | extern PFNGLISBUFFERARBPROC glIsBufferARB; | ||
62 | extern PFNGLBUFFERDATAARBPROC glBufferDataARB; | ||
63 | extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; | ||
64 | extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; | ||
65 | extern PFNGLMAPBUFFERARBPROC glMapBufferARB; | ||
66 | extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; | ||
67 | extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; | ||
68 | extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; | ||
69 | |||
70 | // GL_ATI_vertex_array_object | ||
71 | extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; | ||
72 | extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; | ||
73 | extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; | ||
74 | extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; | ||
75 | extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; | ||
76 | extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; | ||
77 | extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; | ||
78 | extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; | ||
79 | extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; | ||
80 | extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; | ||
81 | extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; | ||
82 | extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; | ||
83 | extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; | ||
84 | |||
85 | // GL_ARB_occlusion_query | ||
86 | extern PFNGLGENQUERIESARBPROC glGenQueriesARB; | ||
87 | extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; | ||
88 | extern PFNGLISQUERYARBPROC glIsQueryARB; | ||
89 | extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; | ||
90 | extern PFNGLENDQUERYARBPROC glEndQueryARB; | ||
91 | extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; | ||
92 | extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; | ||
93 | extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; | ||
94 | |||
95 | // GL_ARB_shader_objects | ||
96 | extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; | ||
97 | extern PFNGLGETHANDLEARBPROC glGetHandleARB; | ||
98 | extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; | ||
99 | extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; | ||
100 | extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; | ||
101 | extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; | ||
102 | extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; | ||
103 | extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; | ||
104 | extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; | ||
105 | extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; | ||
106 | extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; | ||
107 | extern PFNGLUNIFORM1FARBPROC glUniform1fARB; | ||
108 | extern PFNGLUNIFORM2FARBPROC glUniform2fARB; | ||
109 | extern PFNGLUNIFORM3FARBPROC glUniform3fARB; | ||
110 | extern PFNGLUNIFORM4FARBPROC glUniform4fARB; | ||
111 | extern PFNGLUNIFORM1IARBPROC glUniform1iARB; | ||
112 | extern PFNGLUNIFORM2IARBPROC glUniform2iARB; | ||
113 | extern PFNGLUNIFORM3IARBPROC glUniform3iARB; | ||
114 | extern PFNGLUNIFORM4IARBPROC glUniform4iARB; | ||
115 | extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; | ||
116 | extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; | ||
117 | extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; | ||
118 | extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; | ||
119 | extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; | ||
120 | extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; | ||
121 | extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; | ||
122 | extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; | ||
123 | extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; | ||
124 | extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; | ||
125 | extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; | ||
126 | extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; | ||
127 | extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; | ||
128 | extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; | ||
129 | extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; | ||
130 | extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; | ||
131 | extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; | ||
132 | extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; | ||
133 | extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; | ||
134 | extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; | ||
135 | |||
136 | // GL_ARB;_vertex_shader | ||
137 | extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; | ||
138 | extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; | ||
139 | extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; | ||
140 | extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; | ||
141 | extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; | ||
142 | extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; | ||
143 | extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; | ||
144 | extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; | ||
145 | extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; | ||
146 | extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; | ||
147 | extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; | ||
148 | extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; | ||
149 | extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; | ||
150 | extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; | ||
151 | extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; | ||
152 | extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; | ||
153 | extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; | ||
154 | extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; | ||
155 | extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; | ||
156 | extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; | ||
157 | extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; | ||
158 | extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; | ||
159 | extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; | ||
160 | extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; | ||
161 | extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; | ||
162 | extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; | ||
163 | extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; | ||
164 | extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; | ||
165 | extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; | ||
166 | extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; | ||
167 | extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; | ||
168 | extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; | ||
169 | extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; | ||
170 | extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; | ||
171 | extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; | ||
172 | extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; | ||
173 | extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; | ||
174 | extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; | ||
175 | extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; | ||
176 | extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; | ||
177 | extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; | ||
178 | extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; | ||
179 | extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; | ||
180 | extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; | ||
181 | extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; | ||
182 | extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; | ||
183 | extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; | ||
184 | extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; | ||
185 | extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; | ||
186 | extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; | ||
187 | extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; | ||
188 | extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; | ||
189 | extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; | ||
190 | extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; | ||
191 | extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; | ||
192 | extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; | ||
193 | extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; | ||
194 | extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; | ||
195 | extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; | ||
196 | extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; | ||
197 | extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; | ||
198 | extern PFNGLISPROGRAMARBPROC glIsProgramARB; | ||
199 | extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; | ||
200 | extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; | ||
201 | extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; | ||
202 | |||
203 | extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; | ||
204 | extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB; | ||
205 | |||
206 | extern PFNGLCOLORTABLEEXTPROC glColorTableEXT; | ||
207 | |||
208 | #elif LL_WINDOWS | ||
209 | //---------------------------------------------------------------------------- | ||
210 | #include <GL/gl.h> | ||
211 | #include <GL/glu.h> | ||
212 | |||
213 | // quotes so we get libraries/.../GL/ version | ||
214 | #include "GL/glext.h" | ||
215 | #include "GL/glh_extensions.h" | ||
216 | |||
217 | |||
218 | // GL_ARB_vertex_buffer_object | ||
219 | extern PFNGLBINDBUFFERARBPROC glBindBufferARB; | ||
220 | extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; | ||
221 | extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; | ||
222 | extern PFNGLISBUFFERARBPROC glIsBufferARB; | ||
223 | extern PFNGLBUFFERDATAARBPROC glBufferDataARB; | ||
224 | extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB; | ||
225 | extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB; | ||
226 | extern PFNGLMAPBUFFERARBPROC glMapBufferARB; | ||
227 | extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; | ||
228 | extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB; | ||
229 | extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB; | ||
230 | |||
231 | // GL_ATI_vertex_array_object | ||
232 | extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI; | ||
233 | extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI; | ||
234 | extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI; | ||
235 | extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI; | ||
236 | extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI; | ||
237 | extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI; | ||
238 | extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI; | ||
239 | extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI; | ||
240 | extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI; | ||
241 | extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI; | ||
242 | extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; | ||
243 | extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; | ||
244 | extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; | ||
245 | |||
246 | extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; | ||
247 | |||
248 | // GL_ARB_occlusion_query | ||
249 | extern PFNGLGENQUERIESARBPROC glGenQueriesARB; | ||
250 | extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB; | ||
251 | extern PFNGLISQUERYARBPROC glIsQueryARB; | ||
252 | extern PFNGLBEGINQUERYARBPROC glBeginQueryARB; | ||
253 | extern PFNGLENDQUERYARBPROC glEndQueryARB; | ||
254 | extern PFNGLGETQUERYIVARBPROC glGetQueryivARB; | ||
255 | extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB; | ||
256 | extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB; | ||
257 | |||
258 | // GL_ARB_shader_objects | ||
259 | extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; | ||
260 | extern PFNGLGETHANDLEARBPROC glGetHandleARB; | ||
261 | extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB; | ||
262 | extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; | ||
263 | extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB; | ||
264 | extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB; | ||
265 | extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; | ||
266 | extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB; | ||
267 | extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB; | ||
268 | extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; | ||
269 | extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB; | ||
270 | extern PFNGLUNIFORM1FARBPROC glUniform1fARB; | ||
271 | extern PFNGLUNIFORM2FARBPROC glUniform2fARB; | ||
272 | extern PFNGLUNIFORM3FARBPROC glUniform3fARB; | ||
273 | extern PFNGLUNIFORM4FARBPROC glUniform4fARB; | ||
274 | extern PFNGLUNIFORM1IARBPROC glUniform1iARB; | ||
275 | extern PFNGLUNIFORM2IARBPROC glUniform2iARB; | ||
276 | extern PFNGLUNIFORM3IARBPROC glUniform3iARB; | ||
277 | extern PFNGLUNIFORM4IARBPROC glUniform4iARB; | ||
278 | extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB; | ||
279 | extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB; | ||
280 | extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB; | ||
281 | extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB; | ||
282 | extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB; | ||
283 | extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB; | ||
284 | extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB; | ||
285 | extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB; | ||
286 | extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB; | ||
287 | extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB; | ||
288 | extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB; | ||
289 | extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB; | ||
290 | extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; | ||
291 | extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; | ||
292 | extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB; | ||
293 | extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; | ||
294 | extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB; | ||
295 | extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB; | ||
296 | extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB; | ||
297 | extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB; | ||
298 | |||
299 | // GL_ARB;_vertex_shader | ||
300 | extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB; | ||
301 | extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB; | ||
302 | extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB; | ||
303 | extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB; | ||
304 | extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB; | ||
305 | extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB; | ||
306 | extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB; | ||
307 | extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB; | ||
308 | extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB; | ||
309 | extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB; | ||
310 | extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB; | ||
311 | extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB; | ||
312 | extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB; | ||
313 | extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB; | ||
314 | extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB; | ||
315 | extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB; | ||
316 | extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB; | ||
317 | extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB; | ||
318 | extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB; | ||
319 | extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB; | ||
320 | extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB; | ||
321 | extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB; | ||
322 | extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB; | ||
323 | extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB; | ||
324 | extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB; | ||
325 | extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB; | ||
326 | extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB; | ||
327 | extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB; | ||
328 | extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB; | ||
329 | extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB; | ||
330 | extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB; | ||
331 | extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB; | ||
332 | extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB; | ||
333 | extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB; | ||
334 | extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB; | ||
335 | extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB; | ||
336 | extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB; | ||
337 | extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB; | ||
338 | extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB; | ||
339 | extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB; | ||
340 | extern PFNGLBINDPROGRAMARBPROC glBindProgramARB; | ||
341 | extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB; | ||
342 | extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB; | ||
343 | extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB; | ||
344 | extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB; | ||
345 | extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB; | ||
346 | extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB; | ||
347 | extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB; | ||
348 | extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB; | ||
349 | extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB; | ||
350 | extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB; | ||
351 | extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB; | ||
352 | extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB; | ||
353 | extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB; | ||
354 | extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB; | ||
355 | extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB; | ||
356 | extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB; | ||
357 | extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB; | ||
358 | extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB; | ||
359 | extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB; | ||
360 | extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB; | ||
361 | extern PFNGLISPROGRAMARBPROC glIsProgramARB; | ||
362 | extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB; | ||
363 | extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB; | ||
364 | extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB; | ||
365 | |||
366 | |||
367 | #elif LL_DARWIN | ||
368 | //---------------------------------------------------------------------------- | ||
369 | // LL_DARWIN | ||
370 | |||
371 | #include <OpenGL/gl.h> | ||
372 | #include <OpenGL/glu.h> | ||
373 | |||
374 | #define GL_EXT_separate_specular_color 1 | ||
375 | #include <OpenGL/glext.h> | ||
376 | |||
377 | #include "GL/glh_extensions.h" | ||
378 | |||
379 | #ifdef __cplusplus | ||
380 | extern "C" { | ||
381 | #endif | ||
382 | // | ||
383 | // Define vertex buffer object headers on Mac | ||
384 | // | ||
385 | #ifndef GL_ARB_vertex_buffer_object | ||
386 | #define GL_BUFFER_SIZE_ARB 0x8764 | ||
387 | #define GL_BUFFER_USAGE_ARB 0x8765 | ||
388 | #define GL_ARRAY_BUFFER_ARB 0x8892 | ||
389 | #define GL_ELEMENT_ARRAY_BUFFER_ARB 0x8893 | ||
390 | #define GL_ARRAY_BUFFER_BINDING_ARB 0x8894 | ||
391 | #define GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895 | ||
392 | #define GL_VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896 | ||
393 | #define GL_NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897 | ||
394 | #define GL_COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898 | ||
395 | #define GL_INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899 | ||
396 | #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A | ||
397 | #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B | ||
398 | #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C | ||
399 | #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D | ||
400 | #define GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E | ||
401 | #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F | ||
402 | #define GL_READ_ONLY_ARB 0x88B8 | ||
403 | #define GL_WRITE_ONLY_ARB 0x88B9 | ||
404 | #define GL_READ_WRITE_ARB 0x88BA | ||
405 | #define GL_BUFFER_ACCESS_ARB 0x88BB | ||
406 | #define GL_BUFFER_MAPPED_ARB 0x88BC | ||
407 | #define GL_BUFFER_MAP_POINTER_ARB 0x88BD | ||
408 | #define GL_STREAM_DRAW_ARB 0x88E0 | ||
409 | #define GL_STREAM_READ_ARB 0x88E1 | ||
410 | #define GL_STREAM_COPY_ARB 0x88E2 | ||
411 | #define GL_STATIC_DRAW_ARB 0x88E4 | ||
412 | #define GL_STATIC_READ_ARB 0x88E5 | ||
413 | #define GL_STATIC_COPY_ARB 0x88E6 | ||
414 | #define GL_DYNAMIC_DRAW_ARB 0x88E8 | ||
415 | #define GL_DYNAMIC_READ_ARB 0x88E9 | ||
416 | #define GL_DYNAMIC_COPY_ARB 0x88EA | ||
417 | #endif | ||
418 | |||
419 | |||
420 | |||
421 | #ifndef GL_ARB_vertex_buffer_object | ||
422 | /* GL types for handling large vertex buffer objects */ | ||
423 | typedef intptr_t GLintptrARB; | ||
424 | typedef intptr_t GLsizeiptrARB; | ||
425 | #endif | ||
426 | |||
427 | |||
428 | #ifndef GL_ARB_vertex_buffer_object | ||
429 | #define GL_ARB_vertex_buffer_object 1 | ||
430 | #ifdef GL_GLEXT_FUNCTION_POINTERS | ||
431 | typedef void (* glBindBufferARBProcPtr) (GLenum target, GLuint buffer); | ||
432 | typedef void (* glDeleteBufferARBProcPtr) (GLsizei n, const GLuint *buffers); | ||
433 | typedef void (* glGenBuffersARBProcPtr) (GLsizei n, GLuint *buffers); | ||
434 | typedef GLboolean (* glIsBufferARBProcPtr) (GLuint buffer); | ||
435 | typedef void (* glBufferDataARBProcPtr) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); | ||
436 | typedef void (* glBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); | ||
437 | typedef void (* glGetBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); | ||
438 | typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access); | ||
439 | typedef GLboolean (* glUnmapBufferARBProcPtr) (GLenum target); | ||
440 | typedef void (* glGetBufferParameterivARBProcPtr) (GLenum target, GLenum pname, GLint *params); | ||
441 | typedef void (* glGetBufferPointervARBProcPtr) (GLenum target, GLenum pname, GLvoid* *params); | ||
442 | #else | ||
443 | extern void glBindBufferARB (GLenum, GLuint); | ||
444 | extern void glDeleteBuffersARB (GLsizei, const GLuint *); | ||
445 | extern void glGenBuffersARB (GLsizei, GLuint *); | ||
446 | extern GLboolean glIsBufferARB (GLuint); | ||
447 | extern void glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum); | ||
448 | extern void glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *); | ||
449 | extern void glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *); | ||
450 | extern GLvoid* glMapBufferARB (GLenum, GLenum); | ||
451 | extern GLboolean glUnmapBufferARB (GLenum); | ||
452 | extern void glGetBufferParameterivARB (GLenum, GLenum, GLint *); | ||
453 | extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); | ||
454 | #endif /* GL_GLEXT_FUNCTION_POINTERS */ | ||
455 | #endif | ||
456 | |||
457 | // May be needed for DARWIN... | ||
458 | // #ifndef GL_ARB_compressed_tex_image | ||
459 | // #define GL_ARB_compressed_tex_image 1 | ||
460 | // #ifdef GL_GLEXT_FUNCTION_POINTERS | ||
461 | // typedef void (* glCompressedTexImage1D) (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*); | ||
462 | // typedef void (* glCompressedTexImage2D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); | ||
463 | // typedef void (* glCompressedTexImage3D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); | ||
464 | // typedef void (* glCompressedTexSubImage1D) (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
465 | // typedef void (* glCompressedTexSubImage2D) (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
466 | // typedef void (* glCompressedTexSubImage3D) (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
467 | // typedef void (* glGetCompressedTexImage) (GLenum, GLint, GLvoid*); | ||
468 | // #else | ||
469 | // extern void glCompressedTexImage1D (GLenum, GLint, GLenum, GLsizei, GLint, GLsizei, const GLvoid*); | ||
470 | // extern void glCompressedTexImage2D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); | ||
471 | // extern void glCompressedTexImage3D (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*); | ||
472 | // extern void glCompressedTexSubImage1D (GLenum, GLint, GLint, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
473 | // extern void glCompressedTexSubImage2D (GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
474 | // extern void glCompressedTexSubImage3D (GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*); | ||
475 | // extern void glGetCompressedTexImage (GLenum, GLint, GLvoid*); | ||
476 | // #endif /* GL_GLEXT_FUNCTION_POINTERS */ | ||
477 | // #endif | ||
478 | |||
479 | #ifdef __cplusplus | ||
480 | } | ||
481 | #endif | ||
482 | |||
483 | #endif // LL_MESA / LL_WINDOWS / LL_DARWIN | ||
484 | |||
485 | |||
486 | #endif // LL_LLGLHEADERS_H | ||
diff --git a/linden/indra/llwindow/llglstates.h b/linden/indra/llwindow/llglstates.h new file mode 100644 index 0000000..8e67e33 --- /dev/null +++ b/linden/indra/llwindow/llglstates.h | |||
@@ -0,0 +1,339 @@ | |||
1 | /** | ||
2 | * @file llglstates.h | ||
3 | * @brief LLGL states definitions | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | //THIS HEADER SHOULD ONLY BE INCLUDED FROM llgl.h | ||
29 | #ifndef LL_LLGLSTATES_H | ||
30 | #define LL_LLGLSTATES_H | ||
31 | |||
32 | #ifdef WIN32 | ||
33 | # define WIN32_LEAN_AND_MEAN | ||
34 | # include <winsock2.h> | ||
35 | # include <windows.h> | ||
36 | #endif | ||
37 | |||
38 | #if LL_DARWIN | ||
39 | #include <AGL/gl.h> | ||
40 | #else | ||
41 | #include "llglheaders.h" | ||
42 | #endif | ||
43 | |||
44 | //---------------------------------------------------------------------------- | ||
45 | |||
46 | class LLGLDepthTest | ||
47 | { | ||
48 | // Enabled by default | ||
49 | public: | ||
50 | LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled = GL_TRUE, GLenum depth_func = GL_LEQUAL) | ||
51 | : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) | ||
52 | { | ||
53 | if (depth_enabled != sDepthEnabled) | ||
54 | { | ||
55 | if (depth_enabled) glEnable(GL_DEPTH_TEST); | ||
56 | else glDisable(GL_DEPTH_TEST); | ||
57 | sDepthEnabled = depth_enabled; | ||
58 | } | ||
59 | if (depth_func != sDepthFunc) | ||
60 | { | ||
61 | glDepthFunc(depth_func); | ||
62 | sDepthFunc = depth_func; | ||
63 | } | ||
64 | if (write_enabled != sWriteEnabled) | ||
65 | { | ||
66 | glDepthMask(write_enabled); | ||
67 | sWriteEnabled = write_enabled; | ||
68 | } | ||
69 | } | ||
70 | ~LLGLDepthTest() | ||
71 | { | ||
72 | if (sDepthEnabled != mPrevDepthEnabled ) | ||
73 | { | ||
74 | if (mPrevDepthEnabled) glEnable(GL_DEPTH_TEST); | ||
75 | else glDisable(GL_DEPTH_TEST); | ||
76 | sDepthEnabled = mPrevDepthEnabled; | ||
77 | } | ||
78 | if (sDepthFunc != mPrevDepthFunc) | ||
79 | { | ||
80 | glDepthFunc(mPrevDepthFunc); | ||
81 | sDepthFunc = mPrevDepthFunc; | ||
82 | } | ||
83 | if (sWriteEnabled != mPrevWriteEnabled ) | ||
84 | { | ||
85 | glDepthMask(mPrevWriteEnabled); | ||
86 | sWriteEnabled = mPrevWriteEnabled; | ||
87 | } | ||
88 | } | ||
89 | GLboolean mPrevDepthEnabled; | ||
90 | GLenum mPrevDepthFunc; | ||
91 | GLboolean mPrevWriteEnabled; | ||
92 | private: | ||
93 | static GLboolean sDepthEnabled; // defaults to GL_FALSE | ||
94 | static GLenum sDepthFunc; // defaults to GL_LESS | ||
95 | static GLboolean sWriteEnabled; // defaults to GL_TRUE | ||
96 | }; | ||
97 | |||
98 | //---------------------------------------------------------------------------- | ||
99 | |||
100 | class LLGLSDefault | ||
101 | { | ||
102 | protected: | ||
103 | LLGLEnable mTexture2D, mColorMaterial; | ||
104 | LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog, | ||
105 | mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth, | ||
106 | mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT; | ||
107 | public: | ||
108 | LLGLSDefault() | ||
109 | : | ||
110 | // Enable | ||
111 | mTexture2D(GL_TEXTURE_2D), | ||
112 | mColorMaterial(GL_COLOR_MATERIAL), | ||
113 | // Disable | ||
114 | mAlphaTest(GL_ALPHA_TEST), | ||
115 | mBlend(GL_BLEND), | ||
116 | mCullFace(GL_CULL_FACE), | ||
117 | mDither(GL_DITHER), | ||
118 | mFog(GL_FOG), | ||
119 | mLineSmooth(GL_LINE_SMOOTH), | ||
120 | mLineStipple(GL_LINE_STIPPLE), | ||
121 | mNormalize(GL_NORMALIZE), | ||
122 | mPolygonSmooth(GL_POLYGON_SMOOTH), | ||
123 | mTextureGenQ(GL_TEXTURE_GEN_Q), | ||
124 | mTextureGenR(GL_TEXTURE_GEN_R), | ||
125 | mTextureGenS(GL_TEXTURE_GEN_S), | ||
126 | mTextureGenT(GL_TEXTURE_GEN_T) | ||
127 | { } | ||
128 | }; | ||
129 | |||
130 | class LLGLSTexture | ||
131 | { | ||
132 | protected: | ||
133 | LLGLEnable mTexture2D; | ||
134 | public: | ||
135 | LLGLSTexture() | ||
136 | : mTexture2D(GL_TEXTURE_2D) | ||
137 | {} | ||
138 | }; | ||
139 | |||
140 | |||
141 | class LLGLSNoTexture | ||
142 | { | ||
143 | protected: | ||
144 | LLGLDisable mTexture2D; | ||
145 | public: | ||
146 | LLGLSNoTexture() | ||
147 | : mTexture2D(GL_TEXTURE_2D) | ||
148 | {} | ||
149 | }; | ||
150 | |||
151 | class LLGLSObjectSelect // : public LLGLSDefault | ||
152 | { | ||
153 | protected: | ||
154 | LLGLDisable mBlend, mFog, mTexture2D, mAlphaTest; | ||
155 | LLGLEnable mCullFace; | ||
156 | public: | ||
157 | LLGLSObjectSelect() | ||
158 | : mBlend(GL_BLEND), mFog(GL_FOG), mTexture2D(GL_TEXTURE_2D), | ||
159 | mAlphaTest(GL_ALPHA_TEST), | ||
160 | mCullFace(GL_CULL_FACE) | ||
161 | {} | ||
162 | }; | ||
163 | |||
164 | class LLGLSObjectSelectAlpha // : public LLGLSObjectSelect | ||
165 | { | ||
166 | protected: | ||
167 | LLGLEnable mTexture2D, mAlphaTest; | ||
168 | public: | ||
169 | LLGLSObjectSelectAlpha() | ||
170 | : mTexture2D(GL_TEXTURE_2D), mAlphaTest(GL_ALPHA_TEST) | ||
171 | {} | ||
172 | }; | ||
173 | |||
174 | //---------------------------------------------------------------------------- | ||
175 | |||
176 | class LLGLSUIDefault // : public LLGLSDefault | ||
177 | { | ||
178 | protected: | ||
179 | LLGLEnable mBlend, mAlphaTest, mTexture2D; | ||
180 | LLGLDisable mCullFace; | ||
181 | LLGLDepthTest mDepthTest; | ||
182 | public: | ||
183 | LLGLSUIDefault() | ||
184 | : mBlend(GL_BLEND), mAlphaTest(GL_ALPHA_TEST), | ||
185 | mTexture2D(GL_TEXTURE_2D), | ||
186 | mCullFace(GL_CULL_FACE), | ||
187 | mDepthTest(GL_FALSE, GL_TRUE, GL_LEQUAL) | ||
188 | {} | ||
189 | }; | ||
190 | |||
191 | class LLGLSNoAlphaTest // : public LLGLSUIDefault | ||
192 | { | ||
193 | protected: | ||
194 | LLGLDisable mAlphaTest; | ||
195 | public: | ||
196 | LLGLSNoAlphaTest() | ||
197 | : mAlphaTest(GL_ALPHA_TEST) | ||
198 | {} | ||
199 | }; | ||
200 | |||
201 | class LLGLSNoTextureNoAlphaTest // : public LLGLSUIDefault | ||
202 | { | ||
203 | protected: | ||
204 | LLGLDisable mAlphaTest; | ||
205 | LLGLDisable mTexture2D; | ||
206 | public: | ||
207 | LLGLSNoTextureNoAlphaTest() | ||
208 | : mAlphaTest(GL_ALPHA_TEST), | ||
209 | mTexture2D(GL_TEXTURE_2D) | ||
210 | {} | ||
211 | }; | ||
212 | |||
213 | //---------------------------------------------------------------------------- | ||
214 | |||
215 | class LLGLSFog | ||
216 | { | ||
217 | protected: | ||
218 | LLGLEnable mFog; | ||
219 | public: | ||
220 | LLGLSFog() | ||
221 | : mFog(GL_FOG) | ||
222 | {} | ||
223 | }; | ||
224 | |||
225 | class LLGLSNoFog | ||
226 | { | ||
227 | protected: | ||
228 | LLGLDisable mFog; | ||
229 | public: | ||
230 | LLGLSNoFog() | ||
231 | : mFog(GL_FOG) | ||
232 | {} | ||
233 | }; | ||
234 | |||
235 | //---------------------------------------------------------------------------- | ||
236 | |||
237 | class LLGLSPipeline // : public LLGLSDefault | ||
238 | { | ||
239 | protected: | ||
240 | LLGLEnable mCullFace; | ||
241 | LLGLDepthTest mDepthTest; | ||
242 | public: | ||
243 | LLGLSPipeline() | ||
244 | : mCullFace(GL_CULL_FACE), | ||
245 | mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL) | ||
246 | { } | ||
247 | }; | ||
248 | |||
249 | class LLGLSPipelineAlpha // : public LLGLSPipeline | ||
250 | { | ||
251 | protected: | ||
252 | LLGLEnable mBlend, mAlphaTest; | ||
253 | public: | ||
254 | LLGLSPipelineAlpha() | ||
255 | : mBlend(GL_BLEND), | ||
256 | mAlphaTest(GL_ALPHA_TEST) | ||
257 | { } | ||
258 | }; | ||
259 | |||
260 | class LLGLSPipelineEmbossBump // : public LLGLSPipelineAlpha | ||
261 | { | ||
262 | protected: | ||
263 | LLGLDisable mFog; | ||
264 | public: | ||
265 | LLGLSPipelineEmbossBump() | ||
266 | : mFog(GL_FOG) | ||
267 | { } | ||
268 | }; | ||
269 | |||
270 | class LLGLSPipelineSelection // : public LLGLSPipelineAlpha | ||
271 | { | ||
272 | protected: | ||
273 | LLGLDisable mCullFace; | ||
274 | public: | ||
275 | LLGLSPipelineSelection() | ||
276 | : mCullFace(GL_CULL_FACE) | ||
277 | {} | ||
278 | }; | ||
279 | |||
280 | class LLGLSPipelineAvatar // : public LLGLSPipeline | ||
281 | { | ||
282 | protected: | ||
283 | LLGLEnable mNormalize; | ||
284 | public: | ||
285 | LLGLSPipelineAvatar() | ||
286 | : mNormalize(GL_NORMALIZE) | ||
287 | {} | ||
288 | }; | ||
289 | |||
290 | class LLGLSPipelineSkyBox // : public LLGLSPipeline | ||
291 | { | ||
292 | protected: | ||
293 | LLGLDisable mAlphaTest, mCullFace, mFog; | ||
294 | public: | ||
295 | LLGLSPipelineSkyBox() | ||
296 | : mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG) | ||
297 | { } | ||
298 | }; | ||
299 | |||
300 | class LLGLSTracker // : public LLGLSDefault | ||
301 | { | ||
302 | protected: | ||
303 | LLGLEnable mCullFace, mBlend, mAlphaTest; | ||
304 | LLGLDisable mTexture2D; | ||
305 | public: | ||
306 | LLGLSTracker() : | ||
307 | mCullFace(GL_CULL_FACE), | ||
308 | mBlend(GL_BLEND), | ||
309 | mAlphaTest(GL_ALPHA_TEST), | ||
310 | mTexture2D(GL_TEXTURE_2D) | ||
311 | {} | ||
312 | }; | ||
313 | |||
314 | //---------------------------------------------------------------------------- | ||
315 | |||
316 | class LLGLSSpecular | ||
317 | { | ||
318 | public: | ||
319 | LLGLSSpecular(const LLColor4& color, F32 shininess) | ||
320 | { | ||
321 | if (shininess > 0.0f) | ||
322 | { | ||
323 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color.mV); | ||
324 | S32 shiny = (S32)(shininess*128.f); | ||
325 | shiny = llclamp(shiny,0,128); | ||
326 | glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, shiny); | ||
327 | } | ||
328 | } | ||
329 | ~LLGLSSpecular() | ||
330 | { | ||
331 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, LLColor4(0.f,0.f,0.f,0.f).mV); | ||
332 | glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 0); | ||
333 | } | ||
334 | }; | ||
335 | |||
336 | //---------------------------------------------------------------------------- | ||
337 | |||
338 | |||
339 | #endif | ||
diff --git a/linden/indra/llwindow/llglstubs.h b/linden/indra/llwindow/llglstubs.h new file mode 100644 index 0000000..d7f0d94 --- /dev/null +++ b/linden/indra/llwindow/llglstubs.h | |||
@@ -0,0 +1,232 @@ | |||
1 | /** | ||
2 | * @file llglstubs.h | ||
3 | * @brief LLGL stubs header file | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | |||
29 | // bunch of macros that get #included multiple times with GL_FUNC defined | ||
30 | // various ways to make stubs for OpenGL entry points. These are statically | ||
31 | // linked to the app, and call into the real GL, which is dynamically | ||
32 | // loaded at runtime. See llwindowsdl.cpp for current implementation. | ||
33 | |||
34 | #if 1 | ||
35 | GL_FUNC(void,glAlphaFunc,(GLenum f,GLclampf x),(f,x),) | ||
36 | GL_FUNC(void,glBegin,(GLenum e),(e),) | ||
37 | GL_FUNC(void,glBindTexture,(GLenum target,GLuint name),(target,name),) | ||
38 | GL_FUNC(void,glBlendFunc,(GLenum f,GLenum x),(f,x),) | ||
39 | GL_FUNC(void,glCallLists,(GLsizei a,GLenum b,const GLvoid* c),(a,b,c),) | ||
40 | GL_FUNC(void,glClear,(GLbitfield a),(a),) | ||
41 | GL_FUNC(void,glClearColor,(GLclampf r,GLclampf g,GLclampf b,GLclampf a),(r,g,b,a),) | ||
42 | GL_FUNC(void,glClearDepth,(GLclampd x),(x),) | ||
43 | GL_FUNC(void,glColor3f,(GLfloat r,GLfloat g,GLfloat b),(r,g,b),) | ||
44 | GL_FUNC(void,glColor4f,(GLfloat r,GLfloat g,GLfloat b,GLfloat a),(r,g,b,a),) | ||
45 | GL_FUNC(void,glColorMask,(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha),(red,green,blue,alpha),) | ||
46 | GL_FUNC(void,glColorPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size, type, stride, pointer),) | ||
47 | GL_FUNC(void,glCopyTexImage2D,(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border),(target, level, internalFormat, x, y, width, height, border),) | ||
48 | GL_FUNC(void,glCopyTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height),(target, level, xoffset, yoffset, x, y, width, height),) | ||
49 | GL_FUNC(void,glCullFace,(GLenum mode),(mode),) | ||
50 | GL_FUNC(void,glDeleteLists,(GLuint list, GLsizei range),(list,range),) | ||
51 | GL_FUNC(void,glDeleteTextures,(GLsizei n, const GLuint *textures),(n,textures),) | ||
52 | GL_FUNC(void,glDepthFunc,(GLenum func),(func),) | ||
53 | GL_FUNC(void,glDepthMask,(GLboolean flag),(flag),) | ||
54 | GL_FUNC(void,glDisable,(GLenum cap),(cap),) | ||
55 | GL_FUNC(void,glDisableClientState,(GLenum array),(array),) | ||
56 | GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count),(mode,first,count),) | ||
57 | GL_FUNC(void,glDrawBuffer,(GLenum mode),(mode),) | ||
58 | GL_FUNC(void,glEnable,(GLenum cap),(cap),) | ||
59 | GL_FUNC(void,glEnableClientState,(GLenum array),(array),) | ||
60 | GL_FUNC(void,glEnd,(void),(),) | ||
61 | GL_FUNC(void,glEndList,(void),(),) | ||
62 | GL_FUNC(GLuint,glGenLists,(GLsizei range),(range),return) | ||
63 | GL_FUNC(void,glGenTextures,(GLsizei n, GLuint *textures),(n,textures),) | ||
64 | GL_FUNC(GLenum,glGetError,(void),(),return) | ||
65 | GL_FUNC(void,glGetFloatv,(GLenum pname, GLfloat *params),(pname,params),) | ||
66 | GL_FUNC(void,glHint,(GLenum target, GLenum mode),(target,mode),) | ||
67 | GL_FUNC(void,glInterleavedArrays,(GLenum format, GLsizei stride, const GLvoid *pointer),(format,stride,pointer),) | ||
68 | GL_FUNC(GLboolean,glIsTexture,(GLuint texture),(texture),return) | ||
69 | GL_FUNC(void,glLightfv,(GLenum light, GLenum pname, const GLfloat *params),(light,pname,params),) | ||
70 | GL_FUNC(void,glListBase,(GLuint base),(base),) | ||
71 | GL_FUNC(void,glLoadIdentity,(void),(),) | ||
72 | GL_FUNC(void,glLoadMatrixf,(const GLfloat *m),(m),) | ||
73 | GL_FUNC(void,glMatrixMode,(GLenum mode),(mode),) | ||
74 | GL_FUNC(void,glNewList,(GLuint list, GLenum mode),(list,mode),) | ||
75 | GL_FUNC(void,glNormal3f,(GLfloat nx, GLfloat ny, GLfloat nz),(nx,ny,nz),) | ||
76 | GL_FUNC(void,glOrtho,(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar),(left,right,bottom,top,zNear,zFar),) | ||
77 | GL_FUNC(void,glPixelStorei,(GLenum pname, GLint param),(pname,param),) | ||
78 | GL_FUNC(void,glPixelTransferi,(GLenum pname, GLint param),(pname,param),) | ||
79 | GL_FUNC(void,glPointSize,(GLfloat size),(size),) | ||
80 | GL_FUNC(void,glPopMatrix,(void),(),) | ||
81 | GL_FUNC(void,glPushMatrix,(void),(),) | ||
82 | GL_FUNC(void,glReadBuffer,(GLenum mode),(mode),) | ||
83 | GL_FUNC(void,glReadPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels),(x,y,width,height,format,type,pixels),) | ||
84 | GL_FUNC(void,glRotatef,(GLfloat angle, GLfloat x, GLfloat y, GLfloat z),(angle,x,y,z),) | ||
85 | GL_FUNC(void,glScalef,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),) | ||
86 | GL_FUNC(void,glShadeModel,(GLenum mode),(mode),) | ||
87 | GL_FUNC(void,glTexCoord2f,(GLfloat s, GLfloat t),(s,t),) | ||
88 | GL_FUNC(void,glTexCoordPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size,type,stride,pointer),) | ||
89 | GL_FUNC(void,glTexEnvf,(GLenum target, GLenum pname, GLfloat param),(target,pname,param),) | ||
90 | GL_FUNC(void,glTexEnvfv,(GLenum target, GLenum pname, const GLfloat *params),(target,pname,params),) | ||
91 | GL_FUNC(void,glTexEnvi,(GLenum target, GLenum pname, GLint param),(target,pname,param),) | ||
92 | GL_FUNC(void,glTexParameterf,(GLenum target, GLenum pname, GLfloat param),(target,pname,param),) | ||
93 | GL_FUNC(void,glTexParameteri,(GLenum target, GLenum pname, GLint param),(target,pname,param),) | ||
94 | GL_FUNC(void,glTexSubImage2D,(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels),(target,level,xoffset,yoffset,width,height,format,type,pixels),) | ||
95 | GL_FUNC(void,glTranslated,(GLdouble x, GLdouble y, GLdouble z),(x,y,z),) | ||
96 | GL_FUNC(void,glTranslatef,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),) | ||
97 | GL_FUNC(void,glVertex2i,(GLint x, GLint y),(x,y),) | ||
98 | GL_FUNC(void,glVertex2f,(GLfloat x, GLfloat y),(x,y),) | ||
99 | GL_FUNC(void,glVertex3f,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),) | ||
100 | GL_FUNC(void,glVertexPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size,type,stride,pointer),) | ||
101 | GL_FUNC(void,glViewport,(GLint x, GLint y, GLsizei width, GLsizei height),(x,y,width,height),) | ||
102 | GL_FUNC(void,glLockArraysEXT,(GLint first, GLsizei count),(first,count),) | ||
103 | GL_FUNC(void,glUnlockArraysEXT,(void),(),) | ||
104 | GL_FUNC(void,glGetIntegerv,(GLenum pname, GLint *params),(pname,params),) | ||
105 | GL_FUNC(const GLubyte *,glGetString,(GLenum name),(name),return) | ||
106 | GL_FUNC(void,glGetTexLevelParameteriv,(GLenum target, GLint level, GLenum pname, GLint *params),(target,level,pname,params),) | ||
107 | GL_FUNC(void,glMultMatrixd,(const GLdouble *m),(m),) | ||
108 | GL_FUNC(void,glMultMatrixf,(const GLfloat *m),(m),) | ||
109 | GL_FUNC(void,glGetTexImage,(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels),(target,level,format,type,pixels),) | ||
110 | GL_FUNC(void,glTexImage1D,(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels),(target,level,internalFormat,width,border,format,type,pixels),) | ||
111 | GL_FUNC(void,glTexImage2D,(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels),(target,level,internalFormat,width,height,border,format,type,pixels),) | ||
112 | GL_FUNC(void,glTexImage3D,(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels),(target,level,internalformat,width,height,depth,border,format,type,pixels),) | ||
113 | GL_FUNC(void,glDepthRange,(GLclampd near_val, GLclampd far_val),(near_val,far_val),) | ||
114 | GL_FUNC(void,glCallList,(GLuint list),(list),) | ||
115 | GL_FUNC(void,glClearStencil,(GLint s),(s),) | ||
116 | GL_FUNC(void,glColor3d,(GLdouble red, GLdouble green, GLdouble blue),(red,green,blue),) | ||
117 | GL_FUNC(void,glColor3dv,(const GLdouble *v),(v),) | ||
118 | GL_FUNC(void,glColor3fv,(const GLfloat *v),(v),) | ||
119 | GL_FUNC(void,glColor4dv,(const GLdouble *v),(v),) | ||
120 | GL_FUNC(void,glColor4fv,(const GLfloat *v),(v),) | ||
121 | GL_FUNC(void,glColor4ub,(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha),(red,green,blue,alpha),) | ||
122 | GL_FUNC(void,glColor4ubv,(const GLubyte *v),(v),) | ||
123 | GL_FUNC(void,glColorMaterial,(GLenum face, GLenum mode),(face,mode),) | ||
124 | GL_FUNC(void,glClientActiveTextureARB,(GLenum x),(x),) | ||
125 | GL_FUNC(void,glActiveTextureARB,(GLenum texture),(texture),) | ||
126 | GL_FUNC(GLboolean,glAreTexturesResident,(GLsizei n, const GLuint *textures, GLboolean *residences),(n,textures,residences),return) | ||
127 | GL_FUNC(void,glClipPlane,(GLenum plane, const GLdouble *equation),(plane,equation),) | ||
128 | GL_FUNC(void,glBindBufferARB,(GLenum x, GLuint y),(x,y),) | ||
129 | GL_FUNC(void,glDeleteBuffersARB,(GLsizei x, const GLuint *y),(x,y),) | ||
130 | GL_FUNC(void,glGenBuffersARB,(GLsizei x, GLuint *y),(x,y),) | ||
131 | GL_FUNC(void,glBufferDataARB,(GLenum a, GLsizeiptrARB b, const GLvoid *c, GLenum d),(a,b,c,d),) | ||
132 | GL_FUNC(void,glBufferSubDataARB,(GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d),(a,b,c,d),) | ||
133 | GL_FUNC(void,glProgramStringARB,(GLenum a, GLenum b, GLsizei c, const GLvoid *d),(a,b,c,d),) | ||
134 | GL_FUNC(void,glBindProgramARB,(GLenum a, GLuint b),(a,b),) | ||
135 | GL_FUNC(void,glDeleteProgramsARB,(GLsizei a, const GLuint *b),(a,b),) | ||
136 | GL_FUNC(void,glGenProgramsARB,(GLsizei a, GLuint *b),(a,b),) | ||
137 | GL_FUNC(void,glProgramEnvParameter4dARB,(GLenum a, GLuint b, GLdouble c, GLdouble d, GLdouble e, GLdouble f),(a,b,c,d,e,f),) | ||
138 | GL_FUNC(void,glProgramEnvParameter4dvARB,(GLenum a, GLuint b, const GLdouble *c),(a,b,c),) | ||
139 | GL_FUNC(void,glProgramEnvParameter4fARB,(GLenum a, GLuint b, GLfloat c, GLfloat d, GLfloat e, GLfloat f),(a,b,c,d,e,f),) | ||
140 | GL_FUNC(void,glProgramEnvParameter4fvARB,(GLenum a, GLuint b, const GLfloat *c),(a,b,c),) | ||
141 | GL_FUNC(void,glProgramLocalParameter4dARB,(GLenum a, GLuint b, GLdouble c, GLdouble d, GLdouble e, GLdouble f),(a,b,c,d,e,f),) | ||
142 | GL_FUNC(void,glProgramLocalParameter4dvARB,(GLenum a, GLuint b, const GLdouble *c),(a,b,c),) | ||
143 | GL_FUNC(void,glProgramLocalParameter4fARB,(GLenum a, GLuint b, GLfloat c, GLfloat d, GLfloat e, GLfloat f),(a,b,c,d,e,f),) | ||
144 | GL_FUNC(void,glProgramLocalParameter4fvARB,(GLenum a, GLuint b, const GLfloat *c),(a,b,c),) | ||
145 | GL_FUNC(void,glGetProgramEnvParameterdvARB,(GLenum a, GLuint b, GLdouble *c),(a,b,c),) | ||
146 | GL_FUNC(void,glGetProgramEnvParameterfvARB,(GLenum a, GLuint b, GLfloat *c),(a,b,c),) | ||
147 | GL_FUNC(void,glGetProgramLocalParameterdvARB,(GLenum a, GLuint b, GLdouble *c),(a,b,c),) | ||
148 | GL_FUNC(void,glGetProgramLocalParameterfvARB,(GLenum a, GLuint b, GLfloat *c),(a,b,c),) | ||
149 | GL_FUNC(void,glGetProgramivARB,(GLenum a, GLenum b, GLint *c),(a,b,c),) | ||
150 | GL_FUNC(void,glGetProgramStringARB,(GLenum a, GLenum b, GLvoid *c),(a,b,c),) | ||
151 | GL_FUNC(GLboolean,glIsProgramARB,(GLuint a),(a),return) | ||
152 | GL_FUNC(void,glColorTableEXT,(GLenum a, GLenum b, GLsizei c, GLenum d, GLenum e, const GLvoid *f),(a,b,c,d,e,f),) | ||
153 | GL_FUNC(void,glCompressedTexImage2DARB,(GLenum a, GLint b, GLenum c, GLsizei d, GLsizei e, GLint f, GLsizei g, const GLvoid *h),(a,b,c,d,e,f,g,h),) | ||
154 | GL_FUNC(void,glEnableVertexAttribArrayARB,(GLuint a),(a),) | ||
155 | GL_FUNC(void,glDisableVertexAttribArrayARB,(GLuint a),(a),) | ||
156 | GL_FUNC(void,glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices),(mode,count,type,indices),) | ||
157 | GL_FUNC(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels),(width,height,format,type,pixels),) | ||
158 | GL_FUNC(void,glDrawRangeElements,(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices),(mode,start,end,count,type,indices),) | ||
159 | GL_FUNC(void,glFlush,(void),(),) | ||
160 | GL_FUNC(void,glFogf,(GLenum pname, GLfloat param),(pname,param),) | ||
161 | GL_FUNC(void,glFogfv,(GLenum pname, const GLfloat *params),(pname,params),) | ||
162 | GL_FUNC(void,glFogi,(GLenum pname, GLint param),(pname,param),) | ||
163 | GL_FUNC(void,glFrontFace,(GLenum mode),(mode),) | ||
164 | GL_FUNC(void,glGetBooleanv,(GLenum pname, GLboolean *params),(pname,params),) | ||
165 | GL_FUNC(void,glGetDoublev,(GLenum pname, GLdouble *params),(pname,params),) | ||
166 | GL_FUNC(void,glGetMaterialfv,(GLenum face, GLenum pname, GLfloat *params),(face,pname,params),) | ||
167 | GL_FUNC(void,glGetLightfv,(GLenum light, GLenum pname, GLfloat *params),(light,pname,params),) | ||
168 | GL_FUNC(GLboolean,glIsEnabled,(GLenum cap),(cap),return) | ||
169 | GL_FUNC(void,glGetCompressedTexImageARB,(GLenum a, GLint b, GLvoid *c),(a,b,c),) | ||
170 | GL_FUNC(void,glLightf,(GLenum light, GLenum pname, GLfloat param),(light,pname,param),) | ||
171 | GL_FUNC(void,glLightModelfv,(GLenum pname, const GLfloat *params),(pname,params),) | ||
172 | GL_FUNC(void,glLightModeli,(GLenum pname, GLint param),(pname,param),) | ||
173 | GL_FUNC(void,glLightModeliv,(GLenum pname, const GLint *params),(pname,params),) | ||
174 | GL_FUNC(void,glLineStipple,(GLint factor, GLushort pattern),(factor,pattern),) | ||
175 | GL_FUNC(void,glLineWidth,(GLfloat width),(width),) | ||
176 | GL_FUNC(void,glPushAttrib,(GLbitfield mask),(mask),) | ||
177 | GL_FUNC(void,glPopAttrib,(void),(),) | ||
178 | GL_FUNC(void,glLogicOp,(GLenum opcode),(opcode),) | ||
179 | GL_FUNC(void,glMaterialf,(GLenum face, GLenum pname, GLfloat param),(face,pname,param),) | ||
180 | GL_FUNC(void,glMateriali,(GLenum face, GLenum pname, GLint param),(face,pname,param),) | ||
181 | GL_FUNC(void,glMaterialfv,(GLenum face, GLenum pname, const GLfloat *params),(face,pname,params),) | ||
182 | GL_FUNC(void,glNormal3d,(GLdouble nx, GLdouble ny, GLdouble nz),(nx,ny,nz),) | ||
183 | GL_FUNC(void,glNormal3dv,(const GLdouble *v),(v),) | ||
184 | GL_FUNC(void,glNormal3fv,(const GLfloat *v),(v),) | ||
185 | GL_FUNC(void,glNormalPointer,(GLenum type, GLsizei stride, const GLvoid *ptr),(type,stride,ptr),) | ||
186 | GL_FUNC(void,glPolygonMode,(GLenum face, GLenum mode),(face,mode),) | ||
187 | GL_FUNC(void,glPolygonOffset,(GLfloat factor, GLfloat units),(factor,units),) | ||
188 | GL_FUNC(void,glPolygonStipple,(const GLubyte *mask),(mask),) | ||
189 | GL_FUNC(void,glRotated,(GLdouble angle, GLdouble x, GLdouble y, GLdouble z),(angle,x,y,z),) | ||
190 | GL_FUNC(void,glStencilFunc,(GLenum func, GLint ref, GLuint mask),(func,ref,mask),) | ||
191 | GL_FUNC(void,glStencilMask,(GLuint mask),(mask),) | ||
192 | GL_FUNC(void,glScissor,(GLint x, GLint y, GLsizei width, GLsizei height),(x,y,width,height),) | ||
193 | GL_FUNC(void,glStencilOp,(GLenum fail, GLenum zfail, GLenum zpass),(fail,zfail,zpass),) | ||
194 | GL_FUNC(void,glTexCoord2i,(GLint s, GLint t),(s,t),) | ||
195 | GL_FUNC(void,glTexCoord2fv,(const GLfloat *v),(v),) | ||
196 | GL_FUNC(void,glTexGenfv,(GLenum coord, GLenum pname, const GLfloat *params),(coord,pname,params),) | ||
197 | GL_FUNC(void,glTexGeni,(GLenum coord, GLenum pname, GLint param),(coord,pname,param),) | ||
198 | GL_FUNC(void,glTexParameterfv,(GLenum target, GLenum pname, const GLfloat *params),(target,pname,params),) | ||
199 | GL_FUNC(void,glVertex2d,(GLdouble x, GLdouble y),(x,y),) | ||
200 | GL_FUNC(void,glVertex2dv,(const GLdouble *v),(v),) | ||
201 | GL_FUNC(void,glVertex2fv,(const GLfloat *v),(v),) | ||
202 | GL_FUNC(void,glVertex3dv,(const GLdouble *v),(v),) | ||
203 | GL_FUNC(void,glVertex3fv,(const GLfloat *v),(v),) | ||
204 | GL_FUNC(void,glVertex4dv,(const GLdouble *v),(v),) | ||
205 | GL_FUNC(void,glEvalPoint1,(GLint i),(i),) | ||
206 | GL_FUNC(void,glEvalPoint2,(GLint i, GLint j),(i,j),) | ||
207 | GL_FUNC(void,glEvalCoord1f,(GLfloat u),(u),) | ||
208 | GL_FUNC(void,glEvalCoord2f,(GLfloat u, GLfloat v),(u,v),) | ||
209 | GL_FUNC(void,glEvalMesh1,(GLenum mode, GLint i1, GLint i2),(mode,i1,i2),) | ||
210 | GL_FUNC(void,glEvalMesh2,(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2),(mode,i1,i2,j1,j2),) | ||
211 | GL_FUNC(void,glMapGrid1f,(GLint un, GLfloat u1, GLfloat u2),(un,u1,u2),) | ||
212 | GL_FUNC(void,glMapGrid2d,(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2),(un,u1,u2,vn,v1,v2),) | ||
213 | GL_FUNC(void,glMapGrid2f,(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2),(un,u1,u2,vn,v1,v2),) | ||
214 | GL_FUNC(void,glMap1f,(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points),(target,u1,u2,stride,order,points),) | ||
215 | GL_FUNC(void,glMap2f,(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points),(target,u1,u2,ustride,uorder,v1,v2,vstride,vorder,points),) | ||
216 | GL_FUNC(void,glVertexAttribPointerARB,(GLuint a, GLint b, GLenum c, GLboolean d, GLsizei e, const GLvoid *f),(a,b,c,d,e,f),) | ||
217 | GL_FUNC(GLuint,glNewObjectBufferATI,(GLsizei a, const GLvoid *b, GLenum c),(a,b,c),return) | ||
218 | GL_FUNC(void,glUpdateObjectBufferATI,(GLuint a, GLuint b, GLsizei c, const GLvoid *d, GLenum e),(a,b,c,d,e),) | ||
219 | GL_FUNC(void,glFreeObjectBufferATI,(GLuint a),(a),) | ||
220 | GL_FUNC(void,glArrayObjectATI,(GLenum a, GLint b, GLenum c, GLsizei d, GLuint e, GLuint f),(a,b,c,d,e,f),) | ||
221 | GL_FUNC(void,glVertexAttribArrayObjectATI,(GLuint a, GLint b, GLenum c, GLboolean d, GLsizei e, GLuint f, GLuint g),(a,b,c,d,e,f,g),) | ||
222 | |||
223 | // CgGL needs these on Linux... | ||
224 | #if LL_LINUX | ||
225 | GL_FUNC(void*,glXGetCurrentDisplay,(void),(),return) | ||
226 | GL_FUNC(const char *,glXQueryExtensionsString,(void *dpy, int screen),(dpy,screen),return) | ||
227 | GL_FUNC(void*,glXGetProcAddressARB,(const GLubyte *fn),(fn),return) | ||
228 | #endif | ||
229 | #endif | ||
230 | |||
231 | // end of llglstubs.h ... | ||
232 | |||
diff --git a/linden/indra/llwindow/llgltypes.h b/linden/indra/llwindow/llgltypes.h new file mode 100644 index 0000000..52a58b5 --- /dev/null +++ b/linden/indra/llwindow/llgltypes.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * @file llgltypes.h | ||
3 | * @brief LLGL definition | ||
4 | * | ||
5 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LLGLTYPES_H | ||
29 | #define LLGLTYPES_H | ||
30 | |||
31 | #define MAX_GL_TEXTURE_UNITS 16 | ||
32 | |||
33 | typedef U32 LLGLenum; | ||
34 | typedef U32 LLGLuint; | ||
35 | typedef S32 LLGLint; | ||
36 | typedef F32 LLGLfloat; | ||
37 | typedef F64 LLGLdouble; | ||
38 | typedef U8 LLGLboolean; | ||
39 | |||
40 | #endif | ||
diff --git a/linden/indra/llwindow/llkeyboard.cpp b/linden/indra/llwindow/llkeyboard.cpp new file mode 100644 index 0000000..fd6fcdc --- /dev/null +++ b/linden/indra/llwindow/llkeyboard.cpp | |||
@@ -0,0 +1,392 @@ | |||
1 | /** | ||
2 | * @file llkeyboard.cpp | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | #include "indra_constants.h" | ||
30 | #include "llkeyboard.h" | ||
31 | |||
32 | #include "llwindow.h" | ||
33 | |||
34 | |||
35 | // | ||
36 | // Globals | ||
37 | // | ||
38 | |||
39 | LLKeyboard *gKeyboard = NULL; | ||
40 | |||
41 | //static | ||
42 | std::map<KEY,LLString> LLKeyboard::sKeysToNames; | ||
43 | std::map<LLString,KEY> LLKeyboard::sNamesToKeys; | ||
44 | |||
45 | // | ||
46 | // Class Implementation | ||
47 | // | ||
48 | |||
49 | LLKeyboard::LLKeyboard() : mCallbacks(NULL), mNumpadDistinct(ND_NUMLOCK_OFF) | ||
50 | { | ||
51 | S32 i; | ||
52 | |||
53 | // Constructor for LLTimer inits each timer. We want them to | ||
54 | // be constructed without being initialized, so we shut them down here. | ||
55 | for (i = 0; i < KEY_COUNT; i++) | ||
56 | { | ||
57 | mKeyLevelFrameCount[i] = 0; | ||
58 | mKeyLevel[i] = FALSE; | ||
59 | mKeyUp[i] = FALSE; | ||
60 | mKeyDown[i] = FALSE; | ||
61 | mKeyRepeated[i] = FALSE; | ||
62 | } | ||
63 | |||
64 | mInsertMode = LL_KIM_INSERT; | ||
65 | mCurTranslatedKey = KEY_NONE; | ||
66 | |||
67 | addKeyName(' ', "Space" ); | ||
68 | addKeyName(KEY_RETURN, "Enter" ); | ||
69 | addKeyName(KEY_LEFT, "Left" ); | ||
70 | addKeyName(KEY_RIGHT, "Right" ); | ||
71 | addKeyName(KEY_UP, "Up" ); | ||
72 | addKeyName(KEY_DOWN, "Down" ); | ||
73 | addKeyName(KEY_ESCAPE, "Esc" ); | ||
74 | addKeyName(KEY_HOME, "Home" ); | ||
75 | addKeyName(KEY_END, "End" ); | ||
76 | addKeyName(KEY_PAGE_UP, "PgUp" ); | ||
77 | addKeyName(KEY_PAGE_DOWN, "PgDn" ); | ||
78 | addKeyName(KEY_F1, "F1" ); | ||
79 | addKeyName(KEY_F2, "F2" ); | ||
80 | addKeyName(KEY_F3, "F3" ); | ||
81 | addKeyName(KEY_F4, "F4" ); | ||
82 | addKeyName(KEY_F5, "F5" ); | ||
83 | addKeyName(KEY_F6, "F6" ); | ||
84 | addKeyName(KEY_F7, "F7" ); | ||
85 | addKeyName(KEY_F8, "F8" ); | ||
86 | addKeyName(KEY_F9, "F9" ); | ||
87 | addKeyName(KEY_F10, "F10" ); | ||
88 | addKeyName(KEY_F11, "F11" ); | ||
89 | addKeyName(KEY_F12, "F12" ); | ||
90 | addKeyName(KEY_TAB, "Tab" ); | ||
91 | addKeyName(KEY_ADD, "Add" ); | ||
92 | addKeyName(KEY_SUBTRACT, "Subtract" ); | ||
93 | addKeyName(KEY_MULTIPLY, "Multiply" ); | ||
94 | addKeyName(KEY_DIVIDE, "Divide" ); | ||
95 | addKeyName(KEY_PAD_LEFT, "PAD_LEFT" ); | ||
96 | addKeyName(KEY_PAD_RIGHT, "PAD_RIGHT" ); | ||
97 | addKeyName(KEY_PAD_DOWN, "PAD_DOWN" ); | ||
98 | addKeyName(KEY_PAD_UP, "PAD_UP" ); | ||
99 | addKeyName(KEY_PAD_HOME, "PAD_HOME" ); | ||
100 | addKeyName(KEY_PAD_END, "PAD_END" ); | ||
101 | addKeyName(KEY_PAD_PGUP, "PAD_PGUP" ); | ||
102 | addKeyName(KEY_PAD_PGDN, "PAD_PGDN" ); | ||
103 | addKeyName(KEY_PAD_CENTER, "PAD_CENTER" ); | ||
104 | addKeyName(KEY_PAD_INS, "PAD_INS" ); | ||
105 | addKeyName(KEY_PAD_DEL, "PAD_DEL" ); | ||
106 | addKeyName(KEY_PAD_RETURN, "PAD_Enter" ); | ||
107 | addKeyName(KEY_BUTTON0, "PAD_BUTTON0" ); | ||
108 | addKeyName(KEY_BUTTON1, "PAD_BUTTON1" ); | ||
109 | addKeyName(KEY_BUTTON2, "PAD_BUTTON2" ); | ||
110 | addKeyName(KEY_BUTTON3, "PAD_BUTTON3" ); | ||
111 | addKeyName(KEY_BUTTON4, "PAD_BUTTON4" ); | ||
112 | addKeyName(KEY_BUTTON5, "PAD_BUTTON5" ); | ||
113 | addKeyName(KEY_BUTTON6, "PAD_BUTTON6" ); | ||
114 | addKeyName(KEY_BUTTON7, "PAD_BUTTON7" ); | ||
115 | addKeyName(KEY_BUTTON8, "PAD_BUTTON8" ); | ||
116 | addKeyName(KEY_BUTTON9, "PAD_BUTTON9" ); | ||
117 | addKeyName(KEY_BUTTON10, "PAD_BUTTON10" ); | ||
118 | addKeyName(KEY_BUTTON11, "PAD_BUTTON11" ); | ||
119 | addKeyName(KEY_BUTTON12, "PAD_BUTTON12" ); | ||
120 | addKeyName(KEY_BUTTON13, "PAD_BUTTON13" ); | ||
121 | addKeyName(KEY_BUTTON14, "PAD_BUTTON14" ); | ||
122 | addKeyName(KEY_BUTTON15, "PAD_BUTTON15" ); | ||
123 | |||
124 | addKeyName(KEY_BACKSPACE, "Backsp" ); | ||
125 | addKeyName(KEY_DELETE, "Del" ); | ||
126 | addKeyName(KEY_SHIFT, "Shift" ); | ||
127 | addKeyName(KEY_CONTROL, "Ctrl" ); | ||
128 | addKeyName(KEY_ALT, "Alt" ); | ||
129 | addKeyName(KEY_HYPHEN, "-" ); | ||
130 | addKeyName(KEY_EQUALS, "=" ); | ||
131 | addKeyName(KEY_INSERT, "Ins" ); | ||
132 | addKeyName(KEY_CAPSLOCK, "CapsLock" ); | ||
133 | } | ||
134 | |||
135 | |||
136 | LLKeyboard::~LLKeyboard() | ||
137 | { | ||
138 | // nothing | ||
139 | } | ||
140 | |||
141 | void LLKeyboard::addKeyName(KEY key, const LLString& name) | ||
142 | { | ||
143 | sKeysToNames[key] = name; | ||
144 | LLString nameuc = name; | ||
145 | LLString::toUpper(nameuc); | ||
146 | sNamesToKeys[nameuc] = key; | ||
147 | } | ||
148 | |||
149 | // BUG this has to be called when an OS dialog is shown, otherwise modifier key state | ||
150 | // is wrong because the keyup event is never received by the main window. JC | ||
151 | void LLKeyboard::resetKeys() | ||
152 | { | ||
153 | S32 i; | ||
154 | |||
155 | for (i = 0; i < KEY_COUNT; i++) | ||
156 | { | ||
157 | if( mKeyLevel[i] ) | ||
158 | { | ||
159 | mKeyLevel[i] = FALSE; | ||
160 | mKeyLevelFrameCount[i] = 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | for (i = 0; i < KEY_COUNT; i++) | ||
165 | { | ||
166 | mKeyUp[i] = FALSE; | ||
167 | } | ||
168 | |||
169 | for (i = 0; i < KEY_COUNT; i++) | ||
170 | { | ||
171 | mKeyDown[i] = FALSE; | ||
172 | } | ||
173 | |||
174 | for (i = 0; i < KEY_COUNT; i++) | ||
175 | { | ||
176 | mKeyRepeated[i] = FALSE; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) | ||
182 | { | ||
183 | std::map<U16, KEY>::iterator iter; | ||
184 | |||
185 | // Only translate keys in the map, ignore all other keys for now | ||
186 | iter = mTranslateKeyMap.find(os_key); | ||
187 | if (iter == mTranslateKeyMap.end()) | ||
188 | { | ||
189 | //llwarns << "Unknown virtual key " << os_key << llendl; | ||
190 | *out_key = 0; | ||
191 | return FALSE; | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | *out_key = iter->second; | ||
196 | return TRUE; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | |||
201 | U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) | ||
202 | { | ||
203 | std::map<KEY, U16>::iterator iter; | ||
204 | iter = mInvTranslateKeyMap.find(translated_key); | ||
205 | if (iter == mInvTranslateKeyMap.end()) | ||
206 | { | ||
207 | return 0; | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | return iter->second; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | |||
216 | BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) | ||
217 | { | ||
218 | BOOL handled = FALSE; | ||
219 | BOOL repeated = FALSE; | ||
220 | |||
221 | // is this the first time the key went down? | ||
222 | // if so, generate "character" message | ||
223 | if( !mKeyLevel[translated_key] ) | ||
224 | { | ||
225 | mKeyLevel[translated_key] = TRUE; | ||
226 | mKeyLevelTimer[translated_key].reset(); | ||
227 | mKeyLevelFrameCount[translated_key] = 0; | ||
228 | mKeyRepeated[translated_key] = FALSE; | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | // Level is already down, assume it's repeated. | ||
233 | repeated = TRUE; | ||
234 | mKeyRepeated[translated_key] = TRUE; | ||
235 | } | ||
236 | |||
237 | mKeyDown[translated_key] = TRUE; | ||
238 | mCurTranslatedKey = (KEY)translated_key; | ||
239 | handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); | ||
240 | return handled; | ||
241 | } | ||
242 | |||
243 | |||
244 | BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) | ||
245 | { | ||
246 | BOOL handled = FALSE; | ||
247 | if( mKeyLevel[translated_key] ) | ||
248 | { | ||
249 | mKeyLevel[translated_key] = FALSE; | ||
250 | |||
251 | // Only generate key up events if the key is thought to | ||
252 | // be down. This allows you to call resetKeys() in the | ||
253 | // middle of a frame and ignore subsequent KEY_UP | ||
254 | // messages in the same frame. This was causing the | ||
255 | // sequence W<return> in chat to move agents forward. JC | ||
256 | mKeyUp[translated_key] = TRUE; | ||
257 | handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); | ||
258 | } | ||
259 | |||
260 | lldebugst(LLERR_USER_INPUT) << "keyup -" << translated_key << "-" << llendl; | ||
261 | |||
262 | return handled; | ||
263 | } | ||
264 | |||
265 | |||
266 | void LLKeyboard::toggleInsertMode() | ||
267 | { | ||
268 | if (LL_KIM_INSERT == mInsertMode) | ||
269 | { | ||
270 | mInsertMode = LL_KIM_OVERWRITE; | ||
271 | } | ||
272 | else | ||
273 | { | ||
274 | mInsertMode = LL_KIM_INSERT; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | |||
279 | // Returns time in seconds since key was pressed. | ||
280 | F32 LLKeyboard::getKeyElapsedTime(KEY key) | ||
281 | { | ||
282 | return mKeyLevelTimer[key].getElapsedTimeF32(); | ||
283 | } | ||
284 | |||
285 | // Returns time in frames since key was pressed. | ||
286 | S32 LLKeyboard::getKeyElapsedFrameCount(KEY key) | ||
287 | { | ||
288 | return mKeyLevelFrameCount[key]; | ||
289 | } | ||
290 | |||
291 | // static | ||
292 | BOOL LLKeyboard::keyFromString(const LLString& str, KEY *key) | ||
293 | { | ||
294 | LLString instring(str); | ||
295 | size_t length = instring.size(); | ||
296 | |||
297 | if (length < 1) | ||
298 | { | ||
299 | return FALSE; | ||
300 | } | ||
301 | if (length == 1) | ||
302 | { | ||
303 | char ch = toupper(instring[0]); | ||
304 | if (('0' <= ch && ch <= '9') || | ||
305 | ('A' <= ch && ch <= 'Z') || | ||
306 | ('!' <= ch && ch <= '/') || // !"#$%&'()*+,-./ | ||
307 | (':' <= ch && ch <= '@') || // :;<=>?@ | ||
308 | ('[' <= ch && ch <= '`') || // [\]^_` | ||
309 | ('{' <= ch && ch <= '~')) // {|}~ | ||
310 | { | ||
311 | *key = ch; | ||
312 | return TRUE; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | LLString::toUpper(instring); | ||
317 | KEY res = get_if_there(sNamesToKeys, instring, (KEY)0); | ||
318 | if (res != 0) | ||
319 | { | ||
320 | *key = res; | ||
321 | return TRUE; | ||
322 | } | ||
323 | llwarns << "keyFromString failed: " << str << llendl; | ||
324 | return FALSE; | ||
325 | } | ||
326 | |||
327 | |||
328 | // static | ||
329 | LLString LLKeyboard::stringFromKey(KEY key) | ||
330 | { | ||
331 | LLString res = get_if_there(sKeysToNames, key, LLString::null); | ||
332 | if (res.empty()) | ||
333 | { | ||
334 | char buffer[2]; | ||
335 | buffer[0] = key; | ||
336 | buffer[1] = '\0'; | ||
337 | res = LLString(buffer); | ||
338 | } | ||
339 | return res; | ||
340 | } | ||
341 | |||
342 | |||
343 | |||
344 | //static | ||
345 | BOOL LLKeyboard::maskFromString(const LLString& str, MASK *mask) | ||
346 | { | ||
347 | LLString instring(str); | ||
348 | if (instring == "NONE") | ||
349 | { | ||
350 | *mask = MASK_NONE; | ||
351 | return TRUE; | ||
352 | } | ||
353 | else if (instring == "SHIFT") | ||
354 | { | ||
355 | *mask = MASK_SHIFT; | ||
356 | return TRUE; | ||
357 | } | ||
358 | else if (instring == "CTL") | ||
359 | { | ||
360 | *mask = MASK_CONTROL; | ||
361 | return TRUE; | ||
362 | } | ||
363 | else if (instring == "ALT") | ||
364 | { | ||
365 | *mask = MASK_ALT; | ||
366 | return TRUE; | ||
367 | } | ||
368 | else if (instring == "CTL_SHIFT") | ||
369 | { | ||
370 | *mask = MASK_CONTROL | MASK_SHIFT; | ||
371 | return TRUE; | ||
372 | } | ||
373 | else if (instring == "ALT_SHIFT") | ||
374 | { | ||
375 | *mask = MASK_ALT | MASK_SHIFT; | ||
376 | return TRUE; | ||
377 | } | ||
378 | else if (instring == "CTL_ALT") | ||
379 | { | ||
380 | *mask = MASK_CONTROL | MASK_ALT; | ||
381 | return TRUE; | ||
382 | } | ||
383 | else if (instring == "CTL_ALT_SHIFT") | ||
384 | { | ||
385 | *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT; | ||
386 | return TRUE; | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | return FALSE; | ||
391 | } | ||
392 | } | ||
diff --git a/linden/indra/llwindow/llkeyboard.h b/linden/indra/llwindow/llkeyboard.h new file mode 100644 index 0000000..e262ab6 --- /dev/null +++ b/linden/indra/llwindow/llkeyboard.h | |||
@@ -0,0 +1,144 @@ | |||
1 | /** | ||
2 | * @file llkeyboard.h | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLKEYBOARD_H | ||
29 | #define LL_LLKEYBOARD_H | ||
30 | |||
31 | #include <map> | ||
32 | |||
33 | #include "string_table.h" | ||
34 | #include "lltimer.h" | ||
35 | #include "indra_constants.h" | ||
36 | |||
37 | enum EKeystate | ||
38 | { | ||
39 | KEYSTATE_DOWN, | ||
40 | KEYSTATE_LEVEL, | ||
41 | KEYSTATE_UP | ||
42 | }; | ||
43 | |||
44 | typedef void (*LLKeyFunc)(EKeystate keystate); | ||
45 | |||
46 | enum EKeyboardInsertMode | ||
47 | { | ||
48 | LL_KIM_INSERT, | ||
49 | LL_KIM_OVERWRITE | ||
50 | }; | ||
51 | |||
52 | class LLKeyBinding | ||
53 | { | ||
54 | public: | ||
55 | KEY mKey; | ||
56 | MASK mMask; | ||
57 | // const char *mName; // unused | ||
58 | LLKeyFunc mFunction; | ||
59 | }; | ||
60 | |||
61 | class LLWindowCallbacks; | ||
62 | |||
63 | class LLKeyboard | ||
64 | { | ||
65 | public: | ||
66 | typedef enum e_numpad_distinct | ||
67 | { | ||
68 | ND_NEVER, | ||
69 | ND_NUMLOCK_OFF, | ||
70 | ND_NUMLOCK_ON | ||
71 | } ENumpadDistinct; | ||
72 | |||
73 | public: | ||
74 | LLKeyboard(); | ||
75 | virtual ~LLKeyboard(); | ||
76 | |||
77 | void resetKeys(); | ||
78 | |||
79 | |||
80 | F32 getCurKeyElapsedTime() { return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; } | ||
81 | F32 getCurKeyElapsedFrameCount() { return getKeyDown(mCurScanKey) ? (F32)getKeyElapsedFrameCount( mCurScanKey ) : 0.f; } | ||
82 | BOOL getKeyDown(const KEY key) { return mKeyLevel[key]; } | ||
83 | BOOL getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } | ||
84 | |||
85 | BOOL translateKey(const U16 os_key, KEY *translated_key); | ||
86 | U16 inverseTranslateKey(const KEY translated_key); | ||
87 | BOOL handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes | ||
88 | BOOL handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes | ||
89 | |||
90 | |||
91 | virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0; | ||
92 | virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; | ||
93 | |||
94 | // Asynchronously poll the control, alt, and shift keys and set the | ||
95 | // appropriate internal key masks. | ||
96 | virtual void resetMaskKeys() = 0; | ||
97 | virtual void scanKeyboard() = 0; // scans keyboard, calls functions as necessary | ||
98 | // Mac must differentiate between Command = Control for keyboard events | ||
99 | // and Command != Control for mouse events. | ||
100 | virtual MASK currentMask(BOOL for_mouse_event) = 0; | ||
101 | virtual KEY currentKey() { return mCurTranslatedKey; } | ||
102 | |||
103 | EKeyboardInsertMode getInsertMode() { return mInsertMode; } | ||
104 | void toggleInsertMode(); | ||
105 | |||
106 | static BOOL maskFromString(const LLString& str, MASK *mask); // False on failure | ||
107 | static BOOL keyFromString(const LLString& str, KEY *key); // False on failure | ||
108 | static LLString stringFromKey(KEY key); | ||
109 | |||
110 | e_numpad_distinct getNumpadDistinct() { return mNumpadDistinct; } | ||
111 | void setNumpadDistinct(e_numpad_distinct val) { mNumpadDistinct = val; } | ||
112 | |||
113 | void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } | ||
114 | F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. | ||
115 | S32 getKeyElapsedFrameCount( KEY key ); // Returns time in frames since key was pressed. | ||
116 | |||
117 | protected: | ||
118 | void addKeyName(KEY key, const LLString& name); | ||
119 | |||
120 | protected: | ||
121 | std::map<U16, KEY> mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs | ||
122 | std::map<KEY, U16> mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys | ||
123 | LLWindowCallbacks *mCallbacks; | ||
124 | |||
125 | LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set | ||
126 | S32 mKeyLevelFrameCount[KEY_COUNT]; // Frames since level was set | ||
127 | BOOL mKeyLevel[KEY_COUNT]; // Levels | ||
128 | BOOL mKeyRepeated[KEY_COUNT]; // Key was repeated | ||
129 | BOOL mKeyUp[KEY_COUNT]; // Up edge | ||
130 | BOOL mKeyDown[KEY_COUNT]; // Down edge | ||
131 | KEY mCurTranslatedKey; | ||
132 | KEY mCurScanKey; // Used during the scanKeyboard() | ||
133 | |||
134 | e_numpad_distinct mNumpadDistinct; | ||
135 | |||
136 | EKeyboardInsertMode mInsertMode; | ||
137 | |||
138 | static std::map<KEY,LLString> sKeysToNames; | ||
139 | static std::map<LLString,KEY> sNamesToKeys; | ||
140 | }; | ||
141 | |||
142 | extern LLKeyboard *gKeyboard; | ||
143 | |||
144 | #endif | ||
diff --git a/linden/indra/llwindow/llkeyboardmacosx.cpp b/linden/indra/llwindow/llkeyboardmacosx.cpp new file mode 100644 index 0000000..961bb66 --- /dev/null +++ b/linden/indra/llwindow/llkeyboardmacosx.cpp | |||
@@ -0,0 +1,328 @@ | |||
1 | /** | ||
2 | * @file llkeyboardmacosx.cpp | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_DARWIN | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "llkeyboardmacosx.h" | ||
32 | #include "llwindow.h" | ||
33 | |||
34 | #include <Carbon/Carbon.h> | ||
35 | |||
36 | LLKeyboardMacOSX::LLKeyboardMacOSX() | ||
37 | { | ||
38 | // Virtual keycode mapping table. Yes, this was as annoying to generate as it looks. | ||
39 | mTranslateKeyMap[0x00] = 'A'; | ||
40 | mTranslateKeyMap[0x01] = 'S'; | ||
41 | mTranslateKeyMap[0x02] = 'D'; | ||
42 | mTranslateKeyMap[0x03] = 'F'; | ||
43 | mTranslateKeyMap[0x04] = 'H'; | ||
44 | mTranslateKeyMap[0x05] = 'G'; | ||
45 | mTranslateKeyMap[0x06] = 'Z'; | ||
46 | mTranslateKeyMap[0x07] = 'X'; | ||
47 | mTranslateKeyMap[0x08] = 'C'; | ||
48 | mTranslateKeyMap[0x09] = 'V'; | ||
49 | mTranslateKeyMap[0x0b] = 'B'; | ||
50 | mTranslateKeyMap[0x0c] = 'Q'; | ||
51 | mTranslateKeyMap[0x0d] = 'W'; | ||
52 | mTranslateKeyMap[0x0e] = 'E'; | ||
53 | mTranslateKeyMap[0x0f] = 'R'; | ||
54 | mTranslateKeyMap[0x10] = 'Y'; | ||
55 | mTranslateKeyMap[0x11] = 'T'; | ||
56 | mTranslateKeyMap[0x12] = '1'; | ||
57 | mTranslateKeyMap[0x13] = '2'; | ||
58 | mTranslateKeyMap[0x14] = '3'; | ||
59 | mTranslateKeyMap[0x15] = '4'; | ||
60 | mTranslateKeyMap[0x16] = '6'; | ||
61 | mTranslateKeyMap[0x17] = '5'; | ||
62 | mTranslateKeyMap[0x18] = '='; // KEY_EQUALS | ||
63 | mTranslateKeyMap[0x19] = '9'; | ||
64 | mTranslateKeyMap[0x1a] = '7'; | ||
65 | mTranslateKeyMap[0x1b] = '-'; // KEY_HYPHEN | ||
66 | mTranslateKeyMap[0x1c] = '8'; | ||
67 | mTranslateKeyMap[0x1d] = '0'; | ||
68 | mTranslateKeyMap[0x1e] = ']'; | ||
69 | mTranslateKeyMap[0x1f] = 'O'; | ||
70 | mTranslateKeyMap[0x20] = 'U'; | ||
71 | mTranslateKeyMap[0x21] = '['; | ||
72 | mTranslateKeyMap[0x22] = 'I'; | ||
73 | mTranslateKeyMap[0x23] = 'P'; | ||
74 | mTranslateKeyMap[0x24] = KEY_RETURN, | ||
75 | mTranslateKeyMap[0x25] = 'L'; | ||
76 | mTranslateKeyMap[0x26] = 'J'; | ||
77 | mTranslateKeyMap[0x27] = '\''; | ||
78 | mTranslateKeyMap[0x28] = 'K'; | ||
79 | mTranslateKeyMap[0x29] = ';'; | ||
80 | mTranslateKeyMap[0x2a] = '\\'; | ||
81 | mTranslateKeyMap[0x2b] = ','; | ||
82 | mTranslateKeyMap[0x2c] = '/'; | ||
83 | mTranslateKeyMap[0x2d] = 'N'; | ||
84 | mTranslateKeyMap[0x2e] = 'M'; | ||
85 | mTranslateKeyMap[0x2f] = '.'; | ||
86 | mTranslateKeyMap[0x30] = KEY_TAB; | ||
87 | mTranslateKeyMap[0x31] = ' '; // space! | ||
88 | mTranslateKeyMap[0x32] = '`'; | ||
89 | mTranslateKeyMap[0x33] = KEY_BACKSPACE; | ||
90 | mTranslateKeyMap[0x35] = KEY_ESCAPE; | ||
91 | //mTranslateKeyMap[0x37] = 0; // Command key. (not used yet) | ||
92 | mTranslateKeyMap[0x38] = KEY_SHIFT; | ||
93 | mTranslateKeyMap[0x39] = KEY_CAPSLOCK; | ||
94 | mTranslateKeyMap[0x3a] = KEY_ALT; | ||
95 | mTranslateKeyMap[0x3b] = KEY_CONTROL; | ||
96 | mTranslateKeyMap[0x41] = '.'; // keypad | ||
97 | mTranslateKeyMap[0x43] = '*'; // keypad | ||
98 | mTranslateKeyMap[0x45] = '+'; // keypad | ||
99 | mTranslateKeyMap[0x4b] = '/'; // keypad | ||
100 | mTranslateKeyMap[0x4c] = KEY_RETURN; // keypad enter | ||
101 | mTranslateKeyMap[0x4e] = '-'; // keypad | ||
102 | mTranslateKeyMap[0x51] = '='; // keypad | ||
103 | mTranslateKeyMap[0x52] = '0'; // keypad | ||
104 | mTranslateKeyMap[0x53] = '1'; // keypad | ||
105 | mTranslateKeyMap[0x54] = '2'; // keypad | ||
106 | mTranslateKeyMap[0x55] = '3'; // keypad | ||
107 | mTranslateKeyMap[0x56] = '4'; // keypad | ||
108 | mTranslateKeyMap[0x57] = '5'; // keypad | ||
109 | mTranslateKeyMap[0x58] = '6'; // keypad | ||
110 | mTranslateKeyMap[0x59] = '7'; // keypad | ||
111 | mTranslateKeyMap[0x5b] = '8'; // keypad | ||
112 | mTranslateKeyMap[0x5c] = '9'; // keypad | ||
113 | mTranslateKeyMap[0x60] = KEY_F5; | ||
114 | mTranslateKeyMap[0x61] = KEY_F6; | ||
115 | mTranslateKeyMap[0x62] = KEY_F7; | ||
116 | mTranslateKeyMap[0x63] = KEY_F3; | ||
117 | mTranslateKeyMap[0x64] = KEY_F8; | ||
118 | mTranslateKeyMap[0x65] = KEY_F9; | ||
119 | mTranslateKeyMap[0x67] = KEY_F11; | ||
120 | mTranslateKeyMap[0x6d] = KEY_F10; | ||
121 | mTranslateKeyMap[0x6f] = KEY_F12; | ||
122 | mTranslateKeyMap[0x72] = KEY_INSERT; | ||
123 | mTranslateKeyMap[0x73] = KEY_HOME; | ||
124 | mTranslateKeyMap[0x74] = KEY_PAGE_UP; | ||
125 | mTranslateKeyMap[0x75] = KEY_DELETE; | ||
126 | mTranslateKeyMap[0x76] = KEY_F4; | ||
127 | mTranslateKeyMap[0x77] = KEY_END; | ||
128 | mTranslateKeyMap[0x78] = KEY_F2; | ||
129 | mTranslateKeyMap[0x79] = KEY_PAGE_DOWN; | ||
130 | mTranslateKeyMap[0x7a] = KEY_F1; | ||
131 | mTranslateKeyMap[0x7b] = KEY_LEFT; | ||
132 | mTranslateKeyMap[0x7c] = KEY_RIGHT; | ||
133 | mTranslateKeyMap[0x7d] = KEY_DOWN; | ||
134 | mTranslateKeyMap[0x7e] = KEY_UP; | ||
135 | |||
136 | // Build inverse map | ||
137 | std::map<U16, KEY>::iterator iter; | ||
138 | for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) | ||
139 | { | ||
140 | mInvTranslateKeyMap[iter->second] = iter->first; | ||
141 | } | ||
142 | |||
143 | // build numpad maps | ||
144 | mTranslateNumpadMap[0x52] = KEY_PAD_INS; // keypad 0 | ||
145 | mTranslateNumpadMap[0x53] = KEY_PAD_END; // keypad 1 | ||
146 | mTranslateNumpadMap[0x54] = KEY_PAD_DOWN; // keypad 2 | ||
147 | mTranslateNumpadMap[0x55] = KEY_PAD_PGDN; // keypad 3 | ||
148 | mTranslateNumpadMap[0x56] = KEY_PAD_LEFT; // keypad 4 | ||
149 | mTranslateNumpadMap[0x57] = KEY_PAD_CENTER; // keypad 5 | ||
150 | mTranslateNumpadMap[0x58] = KEY_PAD_RIGHT; // keypad 6 | ||
151 | mTranslateNumpadMap[0x59] = KEY_PAD_HOME; // keypad 7 | ||
152 | mTranslateNumpadMap[0x5b] = KEY_PAD_UP; // keypad 8 | ||
153 | mTranslateNumpadMap[0x5c] = KEY_PAD_PGUP; // keypad 9 | ||
154 | mTranslateNumpadMap[0x41] = KEY_PAD_DEL; // keypad . | ||
155 | mTranslateNumpadMap[0x4c] = KEY_PAD_RETURN; // keypad enter | ||
156 | |||
157 | // Build inverse numpad map | ||
158 | for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) | ||
159 | { | ||
160 | mInvTranslateNumpadMap[iter->second] = iter->first; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | void LLKeyboardMacOSX::resetMaskKeys() | ||
165 | { | ||
166 | U32 mask = GetCurrentEventKeyModifiers(); | ||
167 | |||
168 | // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). | ||
169 | // It looks a bit suspicious, as it won't correct for keys that have been released. | ||
170 | // Is this the way it's supposed to work? | ||
171 | |||
172 | if(mask & shiftKey) | ||
173 | { | ||
174 | mKeyLevel[KEY_SHIFT] = TRUE; | ||
175 | } | ||
176 | |||
177 | if(mask & (controlKey)) | ||
178 | { | ||
179 | mKeyLevel[KEY_CONTROL] = TRUE; | ||
180 | } | ||
181 | |||
182 | if(mask & optionKey) | ||
183 | { | ||
184 | mKeyLevel[KEY_ALT] = TRUE; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | static BOOL translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) | ||
190 | { | ||
191 | // Translate the virtual keycode into the keycodes the keyboard system expects. | ||
192 | U16 virtualKey = (mask >> 24) & 0x0000007F; | ||
193 | outKey = macKeyTransArray[virtualKey]; | ||
194 | |||
195 | |||
196 | return(outKey != 0); | ||
197 | } | ||
198 | */ | ||
199 | |||
200 | MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) | ||
201 | { | ||
202 | // translate the mask | ||
203 | MASK out_mask = 0; | ||
204 | |||
205 | if(mask & shiftKey) | ||
206 | { | ||
207 | out_mask |= MASK_SHIFT; | ||
208 | } | ||
209 | |||
210 | if(mask & (controlKey | cmdKey)) | ||
211 | { | ||
212 | out_mask |= MASK_CONTROL; | ||
213 | } | ||
214 | |||
215 | if(mask & optionKey) | ||
216 | { | ||
217 | out_mask |= MASK_ALT; | ||
218 | } | ||
219 | |||
220 | return out_mask; | ||
221 | } | ||
222 | |||
223 | BOOL LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) | ||
224 | { | ||
225 | KEY translated_key = 0; | ||
226 | U32 translated_mask = 0; | ||
227 | BOOL handled = FALSE; | ||
228 | |||
229 | translated_mask = updateModifiers(mask); | ||
230 | |||
231 | if(translateNumpadKey(key, &translated_key)) | ||
232 | { | ||
233 | handled = handleTranslatedKeyDown(translated_key, translated_mask); | ||
234 | } | ||
235 | |||
236 | return handled; | ||
237 | } | ||
238 | |||
239 | |||
240 | BOOL LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) | ||
241 | { | ||
242 | KEY translated_key = 0; | ||
243 | U32 translated_mask = 0; | ||
244 | BOOL handled = FALSE; | ||
245 | |||
246 | translated_mask = updateModifiers(mask); | ||
247 | |||
248 | if(translateNumpadKey(key, &translated_key)) | ||
249 | { | ||
250 | handled = handleTranslatedKeyUp(translated_key, translated_mask); | ||
251 | } | ||
252 | |||
253 | return handled; | ||
254 | } | ||
255 | |||
256 | MASK LLKeyboardMacOSX::currentMask(BOOL for_mouse_event) | ||
257 | { | ||
258 | MASK result = MASK_NONE; | ||
259 | U32 mask = GetCurrentEventKeyModifiers(); | ||
260 | |||
261 | if (mask & shiftKey) result |= MASK_SHIFT; | ||
262 | if (mask & controlKey) result |= MASK_CONTROL; | ||
263 | if (mask & optionKey) result |= MASK_ALT; | ||
264 | |||
265 | // For keyboard events, consider Command equivalent to Control | ||
266 | if (!for_mouse_event) | ||
267 | { | ||
268 | if (mask & cmdKey) result |= MASK_CONTROL; | ||
269 | } | ||
270 | |||
271 | return result; | ||
272 | } | ||
273 | |||
274 | void LLKeyboardMacOSX::scanKeyboard() | ||
275 | { | ||
276 | S32 key; | ||
277 | for (key = 0; key < KEY_COUNT; key++) | ||
278 | { | ||
279 | // Generate callback if any event has occurred on this key this frame. | ||
280 | // Can't just test mKeyLevel, because this could be a slow frame and | ||
281 | // key might have gone down then up. JC | ||
282 | if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) | ||
283 | { | ||
284 | mCurScanKey = key; | ||
285 | mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | // Reset edges for next frame | ||
290 | for (key = 0; key < KEY_COUNT; key++) | ||
291 | { | ||
292 | mKeyUp[key] = FALSE; | ||
293 | mKeyDown[key] = FALSE; | ||
294 | if (mKeyLevel[key]) | ||
295 | { | ||
296 | mKeyLevelFrameCount[key]++; | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | |||
301 | BOOL LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) | ||
302 | { | ||
303 | if(mNumpadDistinct == ND_NUMLOCK_ON) | ||
304 | { | ||
305 | std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key); | ||
306 | if(iter != mTranslateNumpadMap.end()) | ||
307 | { | ||
308 | *translated_key = iter->second; | ||
309 | return TRUE; | ||
310 | } | ||
311 | } | ||
312 | return translateKey(os_key, translated_key); | ||
313 | } | ||
314 | |||
315 | U16 LLKeyboardMacOSX::inverseTranslateNumpadKey(const KEY translated_key) | ||
316 | { | ||
317 | if(mNumpadDistinct == ND_NUMLOCK_ON) | ||
318 | { | ||
319 | std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key); | ||
320 | if(iter != mInvTranslateNumpadMap.end()) | ||
321 | { | ||
322 | return iter->second; | ||
323 | } | ||
324 | } | ||
325 | return inverseTranslateKey(translated_key); | ||
326 | } | ||
327 | |||
328 | #endif // LL_DARWIN | ||
diff --git a/linden/indra/llwindow/llkeyboardmacosx.h b/linden/indra/llwindow/llkeyboardmacosx.h new file mode 100644 index 0000000..a4d9115 --- /dev/null +++ b/linden/indra/llwindow/llkeyboardmacosx.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /** | ||
2 | * @file llkeyboardmacosx.h | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2004-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLKEYBOARDMACOSX_H | ||
29 | #define LL_LLKEYBOARDMACOSX_H | ||
30 | |||
31 | #include "llkeyboard.h" | ||
32 | |||
33 | class LLKeyboardMacOSX : public LLKeyboard | ||
34 | { | ||
35 | public: | ||
36 | LLKeyboardMacOSX(); | ||
37 | /*virtual*/ ~LLKeyboardMacOSX() {}; | ||
38 | |||
39 | /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); | ||
40 | /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); | ||
41 | /*virtual*/ void resetMaskKeys(); | ||
42 | /*virtual*/ MASK currentMask(BOOL for_mouse_event); | ||
43 | /*virtual*/ void scanKeyboard(); | ||
44 | |||
45 | protected: | ||
46 | MASK updateModifiers(const U32 mask); | ||
47 | void setModifierKeyLevel( KEY key, BOOL new_state ); | ||
48 | BOOL translateNumpadKey( const U16 os_key, KEY *translated_key ); | ||
49 | U16 inverseTranslateNumpadKey(const KEY translated_key); | ||
50 | private: | ||
51 | std::map<U16, KEY> mTranslateNumpadMap; // special map for translating OS keys to numpad keys | ||
52 | std::map<KEY, U16> mInvTranslateNumpadMap; // inverse of the above | ||
53 | }; | ||
54 | |||
55 | #endif | ||
diff --git a/linden/indra/llwindow/llkeyboardsdl.cpp b/linden/indra/llwindow/llkeyboardsdl.cpp new file mode 100644 index 0000000..07db986 --- /dev/null +++ b/linden/indra/llwindow/llkeyboardsdl.cpp | |||
@@ -0,0 +1,343 @@ | |||
1 | /** | ||
2 | * @file llkeyboardsdl.cpp | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_SDL | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "llkeyboardsdl.h" | ||
32 | #include "llwindow.h" | ||
33 | #include "SDL/SDL.h" | ||
34 | |||
35 | LLKeyboardSDL::LLKeyboardSDL() | ||
36 | { | ||
37 | // Set up key mapping for SDL - eventually can read this from a file? | ||
38 | // Anything not in the key map gets dropped | ||
39 | // Add default A-Z | ||
40 | |||
41 | // Virtual key mappings from SDL_keysym.h ... | ||
42 | |||
43 | // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... | ||
44 | U16 cur_char; | ||
45 | for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) | ||
46 | { | ||
47 | mTranslateKeyMap[cur_char] = cur_char; | ||
48 | } | ||
49 | for (cur_char = 'a'; cur_char <= 'z'; cur_char++) | ||
50 | { | ||
51 | mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; | ||
52 | } | ||
53 | |||
54 | for (cur_char = '0'; cur_char <= '9'; cur_char++) | ||
55 | { | ||
56 | mTranslateKeyMap[cur_char] = cur_char; | ||
57 | } | ||
58 | |||
59 | // These ones are translated manually upon keydown/keyup because | ||
60 | // SDL doesn't handle their numlock transition. | ||
61 | //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; | ||
62 | //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; | ||
63 | //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; | ||
64 | //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; | ||
65 | //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; | ||
66 | //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; | ||
67 | //mTranslateKeyMap[SDLK_KP1] = KEY_END; | ||
68 | //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; | ||
69 | //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; | ||
70 | //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; | ||
71 | |||
72 | mTranslateKeyMap[SDLK_SPACE] = ' '; | ||
73 | mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN; | ||
74 | mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT; | ||
75 | mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; | ||
76 | mTranslateKeyMap[SDLK_UP] = KEY_UP; | ||
77 | mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; | ||
78 | mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; | ||
79 | mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; | ||
80 | mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; | ||
81 | mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; | ||
82 | mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; | ||
83 | mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; | ||
84 | mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; | ||
85 | mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; | ||
86 | mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; | ||
87 | mTranslateKeyMap[SDLK_LALT] = KEY_ALT; | ||
88 | mTranslateKeyMap[SDLK_RALT] = KEY_ALT; | ||
89 | mTranslateKeyMap[SDLK_HOME] = KEY_HOME; | ||
90 | mTranslateKeyMap[SDLK_END] = KEY_END; | ||
91 | mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; | ||
92 | mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; | ||
93 | mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; | ||
94 | mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; | ||
95 | mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; | ||
96 | mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; | ||
97 | mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; | ||
98 | mTranslateKeyMap[SDLK_TAB] = KEY_TAB; | ||
99 | mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; | ||
100 | mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; | ||
101 | mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; | ||
102 | mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_DIVIDE; | ||
103 | mTranslateKeyMap[SDLK_F1] = KEY_F1; | ||
104 | mTranslateKeyMap[SDLK_F2] = KEY_F2; | ||
105 | mTranslateKeyMap[SDLK_F3] = KEY_F3; | ||
106 | mTranslateKeyMap[SDLK_F4] = KEY_F4; | ||
107 | mTranslateKeyMap[SDLK_F5] = KEY_F5; | ||
108 | mTranslateKeyMap[SDLK_F6] = KEY_F6; | ||
109 | mTranslateKeyMap[SDLK_F7] = KEY_F7; | ||
110 | mTranslateKeyMap[SDLK_F8] = KEY_F8; | ||
111 | mTranslateKeyMap[SDLK_F9] = KEY_F9; | ||
112 | mTranslateKeyMap[SDLK_F10] = KEY_F10; | ||
113 | mTranslateKeyMap[SDLK_F11] = KEY_F11; | ||
114 | mTranslateKeyMap[SDLK_F12] = KEY_F12; | ||
115 | mTranslateKeyMap[SDLK_PLUS] = '='; | ||
116 | mTranslateKeyMap[SDLK_COMMA] = ','; | ||
117 | mTranslateKeyMap[SDLK_MINUS] = '-'; | ||
118 | mTranslateKeyMap[SDLK_PERIOD] = '.'; | ||
119 | mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; | ||
120 | mTranslateKeyMap[SDLK_SLASH] = '/'; | ||
121 | mTranslateKeyMap[SDLK_SEMICOLON] = ';'; | ||
122 | mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; | ||
123 | mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; | ||
124 | mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; | ||
125 | mTranslateKeyMap[SDLK_QUOTE] = '\''; | ||
126 | |||
127 | // Build inverse map | ||
128 | std::map<U16, KEY>::iterator iter; | ||
129 | for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) | ||
130 | { | ||
131 | mInvTranslateKeyMap[iter->second] = iter->first; | ||
132 | } | ||
133 | |||
134 | // numpad map | ||
135 | mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; | ||
136 | mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; | ||
137 | mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; | ||
138 | mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; | ||
139 | mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; | ||
140 | mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; | ||
141 | mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; | ||
142 | mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; | ||
143 | mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; | ||
144 | mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; | ||
145 | mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; | ||
146 | |||
147 | // build inverse numpad map | ||
148 | for (iter = mTranslateNumpadMap.begin(); | ||
149 | iter != mTranslateNumpadMap.end(); | ||
150 | iter++) | ||
151 | { | ||
152 | mInvTranslateNumpadMap[iter->second] = iter->first; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | void LLKeyboardSDL::resetMaskKeys() | ||
157 | { | ||
158 | SDLMod mask = SDL_GetModState(); | ||
159 | |||
160 | // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). | ||
161 | // It looks a bit suspicious, as it won't correct for keys that have been released. | ||
162 | // Is this the way it's supposed to work? | ||
163 | |||
164 | if(mask & KMOD_SHIFT) | ||
165 | { | ||
166 | mKeyLevel[KEY_SHIFT] = TRUE; | ||
167 | } | ||
168 | |||
169 | if(mask & KMOD_CTRL) | ||
170 | { | ||
171 | mKeyLevel[KEY_CONTROL] = TRUE; | ||
172 | } | ||
173 | |||
174 | if(mask & KMOD_ALT) | ||
175 | { | ||
176 | mKeyLevel[KEY_ALT] = TRUE; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | |||
181 | MASK LLKeyboardSDL::updateModifiers(const U32 mask) | ||
182 | { | ||
183 | // translate the mask | ||
184 | MASK out_mask = MASK_NONE; | ||
185 | |||
186 | if(mask & KMOD_SHIFT) | ||
187 | { | ||
188 | out_mask |= MASK_SHIFT; | ||
189 | } | ||
190 | |||
191 | if(mask & KMOD_CTRL) | ||
192 | { | ||
193 | out_mask |= MASK_CONTROL; | ||
194 | } | ||
195 | |||
196 | if(mask & KMOD_ALT) | ||
197 | { | ||
198 | out_mask |= MASK_ALT; | ||
199 | } | ||
200 | |||
201 | return out_mask; | ||
202 | } | ||
203 | |||
204 | |||
205 | static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) | ||
206 | { | ||
207 | // SDL doesn't automatically adjust the keysym according to | ||
208 | // whether NUMLOCK is engaged, so we massage the keysym manually. | ||
209 | U16 rtn = key; | ||
210 | if (!(mask & KMOD_NUM)) | ||
211 | { | ||
212 | switch (key) | ||
213 | { | ||
214 | case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; | ||
215 | case SDLK_KP0: rtn = SDLK_INSERT; break; | ||
216 | case SDLK_KP1: rtn = SDLK_END; break; | ||
217 | case SDLK_KP2: rtn = SDLK_DOWN; break; | ||
218 | case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; | ||
219 | case SDLK_KP4: rtn = SDLK_LEFT; break; | ||
220 | case SDLK_KP6: rtn = SDLK_RIGHT; break; | ||
221 | case SDLK_KP7: rtn = SDLK_HOME; break; | ||
222 | case SDLK_KP8: rtn = SDLK_UP; break; | ||
223 | case SDLK_KP9: rtn = SDLK_PAGEUP; break; | ||
224 | } | ||
225 | } | ||
226 | return rtn; | ||
227 | } | ||
228 | |||
229 | |||
230 | BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) | ||
231 | { | ||
232 | U16 adjusted_nativekey; | ||
233 | KEY translated_key = 0; | ||
234 | U32 translated_mask = MASK_NONE; | ||
235 | BOOL handled = FALSE; | ||
236 | |||
237 | adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); | ||
238 | |||
239 | translated_mask = updateModifiers(mask); | ||
240 | |||
241 | if(translateNumpadKey(adjusted_nativekey, &translated_key)) | ||
242 | { | ||
243 | handled = handleTranslatedKeyDown(translated_key, translated_mask); | ||
244 | } | ||
245 | |||
246 | return handled; | ||
247 | } | ||
248 | |||
249 | |||
250 | BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) | ||
251 | { | ||
252 | U16 adjusted_nativekey; | ||
253 | KEY translated_key = 0; | ||
254 | U32 translated_mask = MASK_NONE; | ||
255 | BOOL handled = FALSE; | ||
256 | |||
257 | adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); | ||
258 | |||
259 | translated_mask = updateModifiers(mask); | ||
260 | |||
261 | if(translateNumpadKey(adjusted_nativekey, &translated_key)) | ||
262 | { | ||
263 | handled = handleTranslatedKeyUp(translated_key, translated_mask); | ||
264 | } | ||
265 | |||
266 | return handled; | ||
267 | } | ||
268 | |||
269 | MASK LLKeyboardSDL::currentMask(BOOL for_mouse_event) | ||
270 | { | ||
271 | MASK result = MASK_NONE; | ||
272 | SDLMod mask = SDL_GetModState(); | ||
273 | |||
274 | if (mask & KMOD_SHIFT) result |= MASK_SHIFT; | ||
275 | if (mask & KMOD_CTRL) result |= MASK_CONTROL; | ||
276 | if (mask & KMOD_ALT) result |= MASK_ALT; | ||
277 | |||
278 | // For keyboard events, consider Meta keys equivalent to Control | ||
279 | if (!for_mouse_event) | ||
280 | { | ||
281 | if (mask & KMOD_META) result |= MASK_CONTROL; | ||
282 | } | ||
283 | |||
284 | return result; | ||
285 | } | ||
286 | |||
287 | void LLKeyboardSDL::scanKeyboard() | ||
288 | { | ||
289 | for (S32 key = 0; key < KEY_COUNT; key++) | ||
290 | { | ||
291 | // Generate callback if any event has occurred on this key this frame. | ||
292 | // Can't just test mKeyLevel, because this could be a slow frame and | ||
293 | // key might have gone down then up. JC | ||
294 | if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) | ||
295 | { | ||
296 | mCurScanKey = key; | ||
297 | mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // Reset edges for next frame | ||
302 | for (S32 key = 0; key < KEY_COUNT; key++) | ||
303 | { | ||
304 | mKeyUp[key] = FALSE; | ||
305 | mKeyDown[key] = FALSE; | ||
306 | if (mKeyLevel[key]) | ||
307 | { | ||
308 | mKeyLevelFrameCount[key]++; | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | |||
313 | |||
314 | BOOL LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) | ||
315 | { | ||
316 | if(mNumpadDistinct == ND_NUMLOCK_ON) | ||
317 | { | ||
318 | std::map<U16, KEY>::iterator iter= mTranslateNumpadMap.find(os_key); | ||
319 | if(iter != mTranslateNumpadMap.end()) | ||
320 | { | ||
321 | *translated_key = iter->second; | ||
322 | return TRUE; | ||
323 | } | ||
324 | } | ||
325 | BOOL success = translateKey(os_key, translated_key); | ||
326 | return success; | ||
327 | } | ||
328 | |||
329 | U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) | ||
330 | { | ||
331 | if(mNumpadDistinct == ND_NUMLOCK_ON) | ||
332 | { | ||
333 | std::map<KEY, U16>::iterator iter= mInvTranslateNumpadMap.find(translated_key); | ||
334 | if(iter != mInvTranslateNumpadMap.end()) | ||
335 | { | ||
336 | return iter->second; | ||
337 | } | ||
338 | } | ||
339 | return inverseTranslateKey(translated_key); | ||
340 | } | ||
341 | |||
342 | #endif | ||
343 | |||
diff --git a/linden/indra/llwindow/llkeyboardsdl.h b/linden/indra/llwindow/llkeyboardsdl.h new file mode 100644 index 0000000..b582e21 --- /dev/null +++ b/linden/indra/llwindow/llkeyboardsdl.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /** | ||
2 | * @file llkeyboardsdl.h | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2004-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLKEYBOARDSDL_H | ||
29 | #define LL_LLKEYBOARDSDL_H | ||
30 | |||
31 | #include "llkeyboard.h" | ||
32 | #include "SDL/SDL.h" | ||
33 | |||
34 | class LLKeyboardSDL : public LLKeyboard | ||
35 | { | ||
36 | public: | ||
37 | LLKeyboardSDL(); | ||
38 | /*virtual*/ ~LLKeyboardSDL() {}; | ||
39 | |||
40 | /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); | ||
41 | /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); | ||
42 | /*virtual*/ void resetMaskKeys(); | ||
43 | /*virtual*/ MASK currentMask(BOOL for_mouse_event); | ||
44 | /*virtual*/ void scanKeyboard(); | ||
45 | |||
46 | protected: | ||
47 | MASK updateModifiers(const U32 mask); | ||
48 | void setModifierKeyLevel( KEY key, BOOL new_state ); | ||
49 | BOOL translateNumpadKey( const U16 os_key, KEY *translated_key ); | ||
50 | U16 inverseTranslateNumpadKey(const KEY translated_key); | ||
51 | private: | ||
52 | std::map<U16, KEY> mTranslateNumpadMap; // special map for translating OS keys to numpad keys | ||
53 | std::map<KEY, U16> mInvTranslateNumpadMap; // inverse of the above | ||
54 | }; | ||
55 | |||
56 | #endif | ||
diff --git a/linden/indra/llwindow/llkeyboardwin32.cpp b/linden/indra/llwindow/llkeyboardwin32.cpp new file mode 100644 index 0000000..531ad87 --- /dev/null +++ b/linden/indra/llwindow/llkeyboardwin32.cpp | |||
@@ -0,0 +1,401 @@ | |||
1 | /** | ||
2 | * @file llkeyboardwin32.cpp | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_WINDOWS | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | |||
32 | #include "llkeyboardwin32.h" | ||
33 | |||
34 | #include "llwindow.h" | ||
35 | |||
36 | #define WIN32_LEAN_AND_MEAN | ||
37 | #include <winsock2.h> | ||
38 | #include <windows.h> | ||
39 | |||
40 | LLKeyboardWin32::LLKeyboardWin32() | ||
41 | { | ||
42 | // Set up key mapping for windows - eventually can read this from a file? | ||
43 | // Anything not in the key map gets dropped | ||
44 | // Add default A-Z | ||
45 | |||
46 | // Virtual key mappings from WinUser.h | ||
47 | |||
48 | KEY cur_char; | ||
49 | for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) | ||
50 | { | ||
51 | mTranslateKeyMap[cur_char] = (KEY)cur_char; | ||
52 | } | ||
53 | |||
54 | for (cur_char = '0'; cur_char <= '9'; cur_char++) | ||
55 | { | ||
56 | mTranslateKeyMap[cur_char] = (KEY)cur_char; | ||
57 | } | ||
58 | // numpad number keys | ||
59 | for (cur_char = 0x60; cur_char <= 0x69; cur_char++) | ||
60 | { | ||
61 | mTranslateKeyMap[cur_char] = (KEY)('0' + (0x60 - cur_char)); | ||
62 | } | ||
63 | |||
64 | |||
65 | mTranslateKeyMap[VK_SPACE] = ' '; | ||
66 | mTranslateKeyMap[VK_OEM_1] = ';'; | ||
67 | // When the user hits, for example, Ctrl-= as a keyboard shortcut, | ||
68 | // Windows generates VK_OEM_PLUS. This is true on both QWERTY and DVORAK | ||
69 | // keyboards in the US. Numeric keypad '+' generates VK_ADD below. | ||
70 | // Thus we translate it as '='. | ||
71 | // Potential bug: This may not be true on international keyboards. JC | ||
72 | mTranslateKeyMap[VK_OEM_PLUS] = '='; | ||
73 | mTranslateKeyMap[VK_OEM_COMMA] = ','; | ||
74 | mTranslateKeyMap[VK_OEM_MINUS] = '-'; | ||
75 | mTranslateKeyMap[VK_OEM_PERIOD] = '.'; | ||
76 | mTranslateKeyMap[VK_OEM_2] = '/'; | ||
77 | mTranslateKeyMap[VK_OEM_3] = '`'; | ||
78 | mTranslateKeyMap[VK_OEM_4] = '['; | ||
79 | mTranslateKeyMap[VK_OEM_5] = '\\'; | ||
80 | mTranslateKeyMap[VK_OEM_6] = ']'; | ||
81 | mTranslateKeyMap[VK_OEM_7] = '\''; | ||
82 | mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE; | ||
83 | mTranslateKeyMap[VK_RETURN] = KEY_RETURN; | ||
84 | mTranslateKeyMap[VK_LEFT] = KEY_LEFT; | ||
85 | mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT; | ||
86 | mTranslateKeyMap[VK_UP] = KEY_UP; | ||
87 | mTranslateKeyMap[VK_DOWN] = KEY_DOWN; | ||
88 | mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE; | ||
89 | mTranslateKeyMap[VK_INSERT] = KEY_INSERT; | ||
90 | mTranslateKeyMap[VK_DELETE] = KEY_DELETE; | ||
91 | mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT; | ||
92 | mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL; | ||
93 | mTranslateKeyMap[VK_MENU] = KEY_ALT; | ||
94 | mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK; | ||
95 | mTranslateKeyMap[VK_HOME] = KEY_HOME; | ||
96 | mTranslateKeyMap[VK_END] = KEY_END; | ||
97 | mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP; | ||
98 | mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN; | ||
99 | mTranslateKeyMap[VK_TAB] = KEY_TAB; | ||
100 | mTranslateKeyMap[VK_ADD] = KEY_ADD; | ||
101 | mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT; | ||
102 | mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY; | ||
103 | mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE; | ||
104 | mTranslateKeyMap[VK_F1] = KEY_F1; | ||
105 | mTranslateKeyMap[VK_F2] = KEY_F2; | ||
106 | mTranslateKeyMap[VK_F3] = KEY_F3; | ||
107 | mTranslateKeyMap[VK_F4] = KEY_F4; | ||
108 | mTranslateKeyMap[VK_F5] = KEY_F5; | ||
109 | mTranslateKeyMap[VK_F6] = KEY_F6; | ||
110 | mTranslateKeyMap[VK_F7] = KEY_F7; | ||
111 | mTranslateKeyMap[VK_F8] = KEY_F8; | ||
112 | mTranslateKeyMap[VK_F9] = KEY_F9; | ||
113 | mTranslateKeyMap[VK_F10] = KEY_F10; | ||
114 | mTranslateKeyMap[VK_F11] = KEY_F11; | ||
115 | mTranslateKeyMap[VK_F12] = KEY_F12; | ||
116 | mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER; | ||
117 | |||
118 | // Build inverse map | ||
119 | std::map<U16, KEY>::iterator iter; | ||
120 | for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) | ||
121 | { | ||
122 | mInvTranslateKeyMap[iter->second] = iter->first; | ||
123 | } | ||
124 | |||
125 | // numpad map | ||
126 | mTranslateNumpadMap[0x60] = KEY_PAD_INS; // keypad 0 | ||
127 | mTranslateNumpadMap[0x61] = KEY_PAD_END; // keypad 1 | ||
128 | mTranslateNumpadMap[0x62] = KEY_PAD_DOWN; // keypad 2 | ||
129 | mTranslateNumpadMap[0x63] = KEY_PAD_PGDN; // keypad 3 | ||
130 | mTranslateNumpadMap[0x64] = KEY_PAD_LEFT; // keypad 4 | ||
131 | mTranslateNumpadMap[0x65] = KEY_PAD_CENTER; // keypad 5 | ||
132 | mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT; // keypad 6 | ||
133 | mTranslateNumpadMap[0x67] = KEY_PAD_HOME; // keypad 7 | ||
134 | mTranslateNumpadMap[0x68] = KEY_PAD_UP; // keypad 8 | ||
135 | mTranslateNumpadMap[0x69] = KEY_PAD_PGUP; // keypad 9 | ||
136 | mTranslateNumpadMap[0x6E] = KEY_PAD_DEL; // keypad . | ||
137 | |||
138 | for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) | ||
139 | { | ||
140 | mInvTranslateNumpadMap[iter->second] = iter->first; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | // Asynchronously poll the control, alt and shift keys and set the | ||
145 | // appropriate states. | ||
146 | // Note: this does not generate edges. | ||
147 | void LLKeyboardWin32::resetMaskKeys() | ||
148 | { | ||
149 | // GetAsyncKeyState returns a short and uses the most significant | ||
150 | // bit to indicate that the key is down. | ||
151 | if (GetAsyncKeyState(VK_SHIFT) & 0x8000) | ||
152 | { | ||
153 | mKeyLevel[KEY_SHIFT] = TRUE; | ||
154 | } | ||
155 | |||
156 | if (GetAsyncKeyState(VK_CONTROL) & 0x8000) | ||
157 | { | ||
158 | mKeyLevel[KEY_CONTROL] = TRUE; | ||
159 | } | ||
160 | |||
161 | if (GetAsyncKeyState(VK_MENU) & 0x8000) | ||
162 | { | ||
163 | mKeyLevel[KEY_ALT] = TRUE; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | |||
168 | //void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state ) | ||
169 | //{ | ||
170 | // if( mKeyLevel[key] != new_state ) | ||
171 | // { | ||
172 | // mKeyLevelFrameCount[key] = 0; | ||
173 | // | ||
174 | // if( new_state ) | ||
175 | // { | ||
176 | // mKeyLevelTimer[key].reset(); | ||
177 | // } | ||
178 | // mKeyLevel[key] = new_state; | ||
179 | // } | ||
180 | //} | ||
181 | |||
182 | |||
183 | MASK LLKeyboardWin32::updateModifiers() | ||
184 | { | ||
185 | //RN: this seems redundant, as we should have already received the appropriate | ||
186 | // messages for the modifier keys | ||
187 | |||
188 | // Scan the modifier keys as of the last Windows key message | ||
189 | // (keydown encoded in high order bit of short) | ||
190 | //setModifierKeyLevel( KEY_SHIFT, GetKeyState(VK_SHIFT) & 0x8000 ); | ||
191 | //setModifierKeyLevel( KEY_CONTROL, GetKeyState(VK_CONTROL) & 0x8000 ); | ||
192 | //setModifierKeyLevel( KEY_ALT, GetKeyState(VK_MENU) & 0x8000 ); | ||
193 | //setModifierKeyLevel( KEY_CAPSLOCK, GetKeyState(VK_CAPITAL) & 0x0001); // Low order bit carries the toggle state. | ||
194 | // Get mask for keyboard events | ||
195 | MASK mask = currentMask(FALSE); | ||
196 | return mask; | ||
197 | } | ||
198 | |||
199 | |||
200 | // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags | ||
201 | BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) | ||
202 | { | ||
203 | KEY translated_key; | ||
204 | U32 translated_mask; | ||
205 | BOOL handled = FALSE; | ||
206 | |||
207 | translated_mask = updateModifiers(); | ||
208 | |||
209 | if (translateExtendedKey(key, mask, &translated_key)) | ||
210 | { | ||
211 | handled = handleTranslatedKeyDown(translated_key, translated_mask); | ||
212 | } | ||
213 | |||
214 | return handled; | ||
215 | } | ||
216 | |||
217 | |||
218 | // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags | ||
219 | BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) | ||
220 | { | ||
221 | KEY translated_key; | ||
222 | U32 translated_mask; | ||
223 | BOOL handled = FALSE; | ||
224 | |||
225 | translated_mask = updateModifiers(); | ||
226 | |||
227 | if (translateExtendedKey(key, mask, &translated_key)) | ||
228 | { | ||
229 | handled = handleTranslatedKeyUp(translated_key, translated_mask); | ||
230 | } | ||
231 | |||
232 | return handled; | ||
233 | } | ||
234 | |||
235 | |||
236 | MASK LLKeyboardWin32::currentMask(BOOL) | ||
237 | { | ||
238 | MASK mask = MASK_NONE; | ||
239 | |||
240 | if (mKeyLevel[KEY_SHIFT]) mask |= MASK_SHIFT; | ||
241 | if (mKeyLevel[KEY_CONTROL]) mask |= MASK_CONTROL; | ||
242 | if (mKeyLevel[KEY_ALT]) mask |= MASK_ALT; | ||
243 | |||
244 | return mask; | ||
245 | } | ||
246 | |||
247 | |||
248 | void LLKeyboardWin32::scanKeyboard() | ||
249 | { | ||
250 | S32 key; | ||
251 | for (key = 0; key < KEY_COUNT; key++) | ||
252 | { | ||
253 | // On Windows, verify key down state. JC | ||
254 | if (mKeyLevel[key]) | ||
255 | { | ||
256 | // *TODO: I KNOW there must be a better way of | ||
257 | // interrogating the key state than this, using async key | ||
258 | // state can cause ALL kinds of bugs - Doug | ||
259 | if (key < KEY_BUTTON0) | ||
260 | { | ||
261 | // ...under windows make sure the key actually still is down. | ||
262 | // ...translate back to windows key | ||
263 | U16 virtual_key = inverseTranslateExtendedKey(key); | ||
264 | // keydown in highest bit | ||
265 | if (!(GetAsyncKeyState(virtual_key) & 0x8000)) | ||
266 | { | ||
267 | //llinfos << "Key up event missed, resetting" << llendl; | ||
268 | mKeyLevel[key] = FALSE; | ||
269 | mKeyLevelFrameCount[key] = 0; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | |||
274 | // Generate callback if any event has occurred on this key this frame. | ||
275 | // Can't just test mKeyLevel, because this could be a slow frame and | ||
276 | // key might have gone down then up. JC | ||
277 | if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) | ||
278 | { | ||
279 | mCurScanKey = key; | ||
280 | mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | // Reset edges for next frame | ||
285 | for (key = 0; key < KEY_COUNT; key++) | ||
286 | { | ||
287 | mKeyUp[key] = FALSE; | ||
288 | mKeyDown[key] = FALSE; | ||
289 | if (mKeyLevel[key]) | ||
290 | { | ||
291 | mKeyLevelFrameCount[key]++; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
296 | BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) | ||
297 | { | ||
298 | if(mNumpadDistinct == ND_NUMLOCK_ON) | ||
299 | { | ||
300 | std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key); | ||
301 | if (iter != mTranslateNumpadMap.end()) | ||
302 | { | ||
303 | *translated_key = iter->second; | ||
304 | return TRUE; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | BOOL success = translateKey(os_key, translated_key); | ||
309 | if(mNumpadDistinct != ND_NEVER) { | ||
310 | if(!success) return success; | ||
311 | if(mask & MASK_EXTENDED) | ||
312 | { | ||
313 | // this is where we'd create new keycodes for extended keys | ||
314 | // the set of extended keys includes the 'normal' arrow keys and | ||
315 | // the pgup/dn/insert/home/end/delete cluster above the arrow keys | ||
316 | // see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx | ||
317 | |||
318 | // only process the return key if numlock is off | ||
319 | if(((mNumpadDistinct == ND_NUMLOCK_OFF && | ||
320 | !(GetKeyState(VK_NUMLOCK) & 1)) | ||
321 | || mNumpadDistinct == ND_NUMLOCK_ON) && | ||
322 | *translated_key == KEY_RETURN) { | ||
323 | *translated_key = KEY_PAD_RETURN; | ||
324 | } | ||
325 | } | ||
326 | else | ||
327 | { | ||
328 | // the non-extended keys, those are in the numpad | ||
329 | switch (*translated_key) | ||
330 | { | ||
331 | case KEY_LEFT: | ||
332 | *translated_key = KEY_PAD_LEFT; break; | ||
333 | case KEY_RIGHT: | ||
334 | *translated_key = KEY_PAD_RIGHT; break; | ||
335 | case KEY_UP: | ||
336 | *translated_key = KEY_PAD_UP; break; | ||
337 | case KEY_DOWN: | ||
338 | *translated_key = KEY_PAD_DOWN; break; | ||
339 | case KEY_HOME: | ||
340 | *translated_key = KEY_PAD_HOME; break; | ||
341 | case KEY_END: | ||
342 | *translated_key = KEY_PAD_END; break; | ||
343 | case KEY_PAGE_UP: | ||
344 | *translated_key = KEY_PAD_PGUP; break; | ||
345 | case KEY_PAGE_DOWN: | ||
346 | *translated_key = KEY_PAD_PGDN; break; | ||
347 | case KEY_INSERT: | ||
348 | *translated_key = KEY_PAD_INS; break; | ||
349 | case KEY_DELETE: | ||
350 | *translated_key = KEY_PAD_DEL; break; | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | return success; | ||
355 | } | ||
356 | |||
357 | U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key) | ||
358 | { | ||
359 | // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number | ||
360 | if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1)) | ||
361 | { | ||
362 | std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key); | ||
363 | if (iter != mInvTranslateNumpadMap.end()) | ||
364 | { | ||
365 | return iter->second; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows | ||
370 | // to regular arrows since Windows doesn't distinguish between them | ||
371 | KEY converted_key = translated_key; | ||
372 | switch (converted_key) | ||
373 | { | ||
374 | case KEY_PAD_LEFT: | ||
375 | converted_key = KEY_LEFT; break; | ||
376 | case KEY_PAD_RIGHT: | ||
377 | converted_key = KEY_RIGHT; break; | ||
378 | case KEY_PAD_UP: | ||
379 | converted_key = KEY_UP; break; | ||
380 | case KEY_PAD_DOWN: | ||
381 | converted_key = KEY_DOWN; break; | ||
382 | case KEY_PAD_HOME: | ||
383 | converted_key = KEY_HOME; break; | ||
384 | case KEY_PAD_END: | ||
385 | converted_key = KEY_END; break; | ||
386 | case KEY_PAD_PGUP: | ||
387 | converted_key = KEY_PAGE_UP; break; | ||
388 | case KEY_PAD_PGDN: | ||
389 | converted_key = KEY_PAGE_DOWN; break; | ||
390 | case KEY_PAD_INS: | ||
391 | converted_key = KEY_INSERT; break; | ||
392 | case KEY_PAD_DEL: | ||
393 | converted_key = KEY_DELETE; break; | ||
394 | case KEY_PAD_RETURN: | ||
395 | converted_key = KEY_RETURN; break; | ||
396 | } | ||
397 | // convert our virtual keys to OS keys | ||
398 | return inverseTranslateKey(converted_key); | ||
399 | } | ||
400 | |||
401 | #endif | ||
diff --git a/linden/indra/llwindow/llkeyboardwin32.h b/linden/indra/llwindow/llkeyboardwin32.h new file mode 100644 index 0000000..1501e8f --- /dev/null +++ b/linden/indra/llwindow/llkeyboardwin32.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /** | ||
2 | * @file llkeyboardwin32.h | ||
3 | * @brief Handler for assignable key bindings | ||
4 | * | ||
5 | * Copyright (c) 2004-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLKEYBOARDWIN32_H | ||
29 | #define LL_LLKEYBOARDWIN32_H | ||
30 | |||
31 | #include "llkeyboard.h" | ||
32 | |||
33 | // this mask distinguishes extended keys, which include non-numpad arrow keys | ||
34 | // (and, curiously, the num lock and numpad '/') | ||
35 | const MASK MASK_EXTENDED = 0x0100; | ||
36 | |||
37 | class LLKeyboardWin32 : public LLKeyboard | ||
38 | { | ||
39 | public: | ||
40 | LLKeyboardWin32(); | ||
41 | /*virtual*/ ~LLKeyboardWin32() {}; | ||
42 | |||
43 | /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); | ||
44 | /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); | ||
45 | /*virtual*/ void resetMaskKeys(); | ||
46 | /*virtual*/ MASK currentMask(BOOL for_mouse_event); | ||
47 | /*virtual*/ void scanKeyboard(); | ||
48 | BOOL translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); | ||
49 | U16 inverseTranslateExtendedKey(const KEY translated_key); | ||
50 | |||
51 | protected: | ||
52 | MASK updateModifiers(); | ||
53 | //void setModifierKeyLevel( KEY key, BOOL new_state ); | ||
54 | private: | ||
55 | std::map<U16, KEY> mTranslateNumpadMap; | ||
56 | std::map<KEY, U16> mInvTranslateNumpadMap; | ||
57 | }; | ||
58 | |||
59 | #endif | ||
diff --git a/linden/indra/llwindow/llmousehandler.h b/linden/indra/llwindow/llmousehandler.h new file mode 100644 index 0000000..b907b55 --- /dev/null +++ b/linden/indra/llwindow/llmousehandler.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /** | ||
2 | * @file llmousehandler.h | ||
3 | * @brief LLMouseHandler class definition | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_MOUSEHANDLER_H | ||
29 | #define LL_MOUSEHANDLER_H | ||
30 | |||
31 | // Abstract interface. | ||
32 | // Intended for use via multiple inheritance. | ||
33 | // A class may have as many interfaces as it likes, but never needs to inherit one more than once. | ||
34 | |||
35 | class LLMouseHandler | ||
36 | { | ||
37 | public: | ||
38 | LLMouseHandler() {} | ||
39 | virtual ~LLMouseHandler() {} | ||
40 | |||
41 | virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; | ||
42 | virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; | ||
43 | virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; | ||
44 | virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; | ||
45 | virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) = 0; | ||
46 | virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; | ||
47 | virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; | ||
48 | virtual BOOL handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) = 0; | ||
49 | virtual const LLString& getName() const = 0; | ||
50 | |||
51 | // Hack to support LLFocusMgr | ||
52 | virtual BOOL isView() = 0; | ||
53 | |||
54 | virtual void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const = 0; | ||
55 | virtual void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const = 0; | ||
56 | }; | ||
57 | |||
58 | #endif | ||
diff --git a/linden/indra/llwindow/llwindow.cpp b/linden/indra/llwindow/llwindow.cpp new file mode 100644 index 0000000..20fc84e --- /dev/null +++ b/linden/indra/llwindow/llwindow.cpp | |||
@@ -0,0 +1,420 @@ | |||
1 | /** | ||
2 | * @file llwindow.cpp | ||
3 | * @brief Basic graphical window class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | #include "llwindowheadless.h" | ||
30 | |||
31 | #if LL_MESA_HEADLESS | ||
32 | #include "llwindowmesaheadless.h" | ||
33 | #elif LL_SDL | ||
34 | #include "llwindowsdl.h" | ||
35 | #elif LL_WINDOWS | ||
36 | #include "llwindowwin32.h" | ||
37 | #elif LL_DARWIN | ||
38 | #include "llwindowmacosx.h" | ||
39 | #elif LL_LINUX | ||
40 | #include "llwindowlinux.h" // currently just a dummy wrapper | ||
41 | #endif | ||
42 | |||
43 | #include "llerror.h" | ||
44 | #include "llkeyboard.h" | ||
45 | #include "linked_lists.h" | ||
46 | |||
47 | //static instance for default callbacks | ||
48 | LLWindowCallbacks LLWindow::sDefaultCallbacks; | ||
49 | |||
50 | // | ||
51 | // LLWindowCallbacks | ||
52 | // | ||
53 | |||
54 | LLSplashScreen *gSplashScreenp = NULL; | ||
55 | BOOL gDebugClicks = FALSE; | ||
56 | BOOL gDebugWindowProc = FALSE; | ||
57 | |||
58 | const S32 gURLProtocolWhitelistCount = 3; | ||
59 | const char* gURLProtocolWhitelist[] = { "file", "http", "https" }; | ||
60 | |||
61 | // CP: added a handler list - this is what's used to open the protocol and is based on registry entry | ||
62 | // only meaningful difference currently is that file: protocols are opened using http: | ||
63 | // since no protocol handler exists in registry for file: | ||
64 | // Important - these lists should match - protocol to handler | ||
65 | const char* gURLProtocolWhitelistHandler[] = { "http", "http", "https" }; | ||
66 | |||
67 | BOOL LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, BOOL repeated) | ||
68 | { | ||
69 | return FALSE; | ||
70 | } | ||
71 | |||
72 | |||
73 | BOOL LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask) | ||
74 | { | ||
75 | return FALSE; | ||
76 | } | ||
77 | |||
78 | void LLWindowCallbacks::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) | ||
79 | { | ||
80 | } | ||
81 | |||
82 | BOOL LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask) | ||
83 | { | ||
84 | return FALSE; | ||
85 | } | ||
86 | |||
87 | |||
88 | BOOL LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
89 | { | ||
90 | return FALSE; | ||
91 | } | ||
92 | |||
93 | BOOL LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
94 | { | ||
95 | return FALSE; | ||
96 | } | ||
97 | |||
98 | void LLWindowCallbacks::handleMouseLeave(LLWindow *window) | ||
99 | { | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | BOOL LLWindowCallbacks::handleCloseRequest(LLWindow *window) | ||
104 | { | ||
105 | //allow the window to close | ||
106 | return TRUE; | ||
107 | } | ||
108 | |||
109 | void LLWindowCallbacks::handleQuit(LLWindow *window) | ||
110 | { | ||
111 | if(LLWindowManager::destroyWindow(window) == FALSE) | ||
112 | { | ||
113 | llerrs << "LLWindowCallbacks::handleQuit() : Couldn't destroy window" << llendl; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | BOOL LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
118 | { | ||
119 | return FALSE; | ||
120 | } | ||
121 | |||
122 | BOOL LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
123 | { | ||
124 | return FALSE; | ||
125 | } | ||
126 | |||
127 | BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated) | ||
128 | { | ||
129 | return FALSE; | ||
130 | } | ||
131 | |||
132 | void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
133 | { | ||
134 | } | ||
135 | |||
136 | void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) | ||
137 | { | ||
138 | } | ||
139 | |||
140 | void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) | ||
141 | { | ||
142 | } | ||
143 | |||
144 | void LLWindowCallbacks::handleFocus(LLWindow *window) | ||
145 | { | ||
146 | } | ||
147 | |||
148 | void LLWindowCallbacks::handleFocusLost(LLWindow *window) | ||
149 | { | ||
150 | } | ||
151 | |||
152 | void LLWindowCallbacks::handleMenuSelect(LLWindow *window, const S32 menu_item) | ||
153 | { | ||
154 | } | ||
155 | |||
156 | BOOL LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y, | ||
157 | const S32 width, const S32 height) | ||
158 | { | ||
159 | return FALSE; | ||
160 | } | ||
161 | |||
162 | BOOL LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask) | ||
163 | { | ||
164 | return FALSE; | ||
165 | } | ||
166 | |||
167 | void LLWindowCallbacks::handleWindowBlock(LLWindow *window) | ||
168 | { | ||
169 | } | ||
170 | |||
171 | void LLWindowCallbacks::handleWindowUnblock(LLWindow *window) | ||
172 | { | ||
173 | } | ||
174 | |||
175 | void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *data) | ||
176 | { | ||
177 | } | ||
178 | |||
179 | |||
180 | S32 OSMessageBox(const char* text, const char* caption, U32 type) | ||
181 | { | ||
182 | // Properly hide the splash screen when displaying the message box | ||
183 | BOOL was_visible = FALSE; | ||
184 | if (LLSplashScreen::isVisible()) | ||
185 | { | ||
186 | was_visible = TRUE; | ||
187 | LLSplashScreen::hide(); | ||
188 | } | ||
189 | |||
190 | S32 result = 0; | ||
191 | #if LL_MESA_HEADLESS // !!! *FIX: (???) | ||
192 | llwarns << "OSMessageBox: " << text << llendl; | ||
193 | return OSBTN_OK; | ||
194 | #elif LL_WINDOWS | ||
195 | result = OSMessageBoxWin32(text, caption, type); | ||
196 | #elif LL_DARWIN | ||
197 | result = OSMessageBoxMacOSX(text, caption, type); | ||
198 | #elif LL_SDL | ||
199 | result = OSMessageBoxSDL(text, caption, type); | ||
200 | #else | ||
201 | #error("OSMessageBox not implemented for this platform!") | ||
202 | #endif | ||
203 | |||
204 | if (was_visible) | ||
205 | { | ||
206 | LLSplashScreen::show(); | ||
207 | } | ||
208 | |||
209 | return result; | ||
210 | } | ||
211 | |||
212 | |||
213 | // | ||
214 | // LLWindow | ||
215 | // | ||
216 | |||
217 | LLWindow::LLWindow(BOOL fullscreen, U32 flags) | ||
218 | : mCallbacks(&sDefaultCallbacks), | ||
219 | mPostQuit(TRUE), | ||
220 | mFullscreen(fullscreen), | ||
221 | mFullscreenWidth(0), | ||
222 | mFullscreenHeight(0), | ||
223 | mFullscreenBits(0), | ||
224 | mFullscreenRefresh(0), | ||
225 | mSupportedResolutions(NULL), | ||
226 | mNumSupportedResolutions(0), | ||
227 | mCurrentCursor(UI_CURSOR_ARROW), | ||
228 | mCursorHidden(FALSE), | ||
229 | mBusyCount(0), | ||
230 | mIsMouseClipping(FALSE), | ||
231 | mSwapMethod(SWAP_METHOD_UNDEFINED), | ||
232 | mHideCursorPermanent(FALSE), | ||
233 | mFlags(flags) | ||
234 | { | ||
235 | } | ||
236 | |||
237 | // virtual | ||
238 | void LLWindow::incBusyCount() | ||
239 | { | ||
240 | ++mBusyCount; | ||
241 | } | ||
242 | |||
243 | // virtual | ||
244 | void LLWindow::decBusyCount() | ||
245 | { | ||
246 | if (mBusyCount > 0) | ||
247 | { | ||
248 | --mBusyCount; | ||
249 | } | ||
250 | } | ||
251 | |||
252 | void LLWindow::setCallbacks(LLWindowCallbacks *callbacks) | ||
253 | { | ||
254 | mCallbacks = callbacks; | ||
255 | if (gKeyboard) | ||
256 | { | ||
257 | gKeyboard->setCallbacks(callbacks); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | // | ||
262 | // LLSplashScreen | ||
263 | // | ||
264 | |||
265 | // static | ||
266 | bool LLSplashScreen::isVisible() | ||
267 | { | ||
268 | return gSplashScreenp ? true: false; | ||
269 | } | ||
270 | |||
271 | // static | ||
272 | LLSplashScreen *LLSplashScreen::create() | ||
273 | { | ||
274 | #if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (???) | ||
275 | return 0; | ||
276 | #elif LL_WINDOWS | ||
277 | return new LLSplashScreenWin32; | ||
278 | #elif LL_DARWIN | ||
279 | return new LLSplashScreenMacOSX; | ||
280 | #else | ||
281 | #error("LLSplashScreen not implemented on this platform!") | ||
282 | #endif | ||
283 | } | ||
284 | |||
285 | |||
286 | //static | ||
287 | void LLSplashScreen::show() | ||
288 | { | ||
289 | if (!gSplashScreenp) | ||
290 | { | ||
291 | #if LL_WINDOWS && !LL_MESA_HEADLESS | ||
292 | gSplashScreenp = new LLSplashScreenWin32; | ||
293 | #elif LL_DARWIN | ||
294 | gSplashScreenp = new LLSplashScreenMacOSX; | ||
295 | #endif | ||
296 | if (gSplashScreenp) | ||
297 | { | ||
298 | gSplashScreenp->showImpl(); | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | |||
303 | //static | ||
304 | void LLSplashScreen::update(const char* str) | ||
305 | { | ||
306 | LLSplashScreen::show(); | ||
307 | if (gSplashScreenp) | ||
308 | { | ||
309 | gSplashScreenp->updateImpl(str); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | //static | ||
314 | void LLSplashScreen::hide() | ||
315 | { | ||
316 | if (gSplashScreenp) | ||
317 | { | ||
318 | gSplashScreenp->hideImpl(); | ||
319 | } | ||
320 | delete gSplashScreenp; | ||
321 | gSplashScreenp = NULL; | ||
322 | } | ||
323 | |||
324 | // | ||
325 | // LLWindowManager | ||
326 | // | ||
327 | |||
328 | // TODO: replace with std::set | ||
329 | static LLLinkedList<LLWindow> sWindowList; | ||
330 | |||
331 | LLWindow* LLWindowManager::createWindow( | ||
332 | char *title, | ||
333 | char *name, | ||
334 | LLCoordScreen upper_left, | ||
335 | LLCoordScreen size, | ||
336 | U32 flags, | ||
337 | BOOL fullscreen, | ||
338 | BOOL clearBg, | ||
339 | BOOL disable_vsync, | ||
340 | BOOL use_gl, | ||
341 | BOOL ignore_pixel_depth) | ||
342 | { | ||
343 | return createWindow( | ||
344 | title, name, upper_left.mX, upper_left.mY, size.mX, size.mY, flags, | ||
345 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
346 | } | ||
347 | |||
348 | LLWindow* LLWindowManager::createWindow( | ||
349 | char *title, char *name, S32 x, S32 y, S32 width, S32 height, U32 flags, | ||
350 | BOOL fullscreen, | ||
351 | BOOL clearBg, | ||
352 | BOOL disable_vsync, | ||
353 | BOOL use_gl, | ||
354 | BOOL ignore_pixel_depth) | ||
355 | { | ||
356 | LLWindow* new_window; | ||
357 | |||
358 | if (use_gl) | ||
359 | { | ||
360 | #if LL_MESA_HEADLESS | ||
361 | new_window = new LLWindowMesaHeadless( | ||
362 | title, name, x, y, width, height, flags, | ||
363 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
364 | #elif LL_SDL | ||
365 | new_window = new LLWindowSDL( | ||
366 | title, x, y, width, height, flags, | ||
367 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
368 | #elif LL_WINDOWS | ||
369 | new_window = new LLWindowWin32( | ||
370 | title, name, x, y, width, height, flags, | ||
371 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
372 | #elif LL_DARWIN | ||
373 | new_window = new LLWindowMacOSX( | ||
374 | title, name, x, y, width, height, flags, | ||
375 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
376 | #elif LL_LINUX | ||
377 | new_window = new LLWindowLinux( | ||
378 | title, name, x, y, width, height, flags, | ||
379 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
380 | #endif | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | new_window = new LLWindowHeadless( | ||
385 | title, name, x, y, width, height, flags, | ||
386 | fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); | ||
387 | } | ||
388 | |||
389 | if (FALSE == new_window->isValid()) | ||
390 | { | ||
391 | delete new_window; | ||
392 | llwarns << "LLWindowManager::create() : Error creating window." << llendl; | ||
393 | return NULL; | ||
394 | } | ||
395 | sWindowList.addDataAtEnd(new_window); | ||
396 | return new_window; | ||
397 | } | ||
398 | |||
399 | BOOL LLWindowManager::destroyWindow(LLWindow* window) | ||
400 | { | ||
401 | if (!sWindowList.checkData(window)) | ||
402 | { | ||
403 | llerrs << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" | ||
404 | << llendl; | ||
405 | return FALSE; | ||
406 | } | ||
407 | |||
408 | window->close(); | ||
409 | |||
410 | sWindowList.removeData(window); | ||
411 | |||
412 | delete window; | ||
413 | |||
414 | return TRUE; | ||
415 | } | ||
416 | |||
417 | BOOL LLWindowManager::isWindowValid(LLWindow *window) | ||
418 | { | ||
419 | return sWindowList.checkData(window); | ||
420 | } | ||
diff --git a/linden/indra/llwindow/llwindow.h b/linden/indra/llwindow/llwindow.h new file mode 100644 index 0000000..ac427f1 --- /dev/null +++ b/linden/indra/llwindow/llwindow.h | |||
@@ -0,0 +1,334 @@ | |||
1 | /** | ||
2 | * @file llwindow.h | ||
3 | * @brief Basic graphical window class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOW_H | ||
29 | #define LL_LLWINDOW_H | ||
30 | |||
31 | #include <sys/stat.h> | ||
32 | |||
33 | #include "llrect.h" | ||
34 | #include "llcoord.h" | ||
35 | #include "llstring.h" | ||
36 | |||
37 | |||
38 | enum ECursorType { | ||
39 | UI_CURSOR_ARROW, | ||
40 | UI_CURSOR_WAIT, | ||
41 | UI_CURSOR_HAND, | ||
42 | UI_CURSOR_IBEAM, | ||
43 | UI_CURSOR_CROSS, | ||
44 | UI_CURSOR_SIZENWSE, | ||
45 | UI_CURSOR_SIZENESW, | ||
46 | UI_CURSOR_SIZEWE, | ||
47 | UI_CURSOR_SIZENS, | ||
48 | UI_CURSOR_NO, | ||
49 | UI_CURSOR_WORKING, | ||
50 | UI_CURSOR_TOOLGRAB, | ||
51 | UI_CURSOR_TOOLLAND, | ||
52 | UI_CURSOR_TOOLFOCUS, | ||
53 | UI_CURSOR_TOOLCREATE, | ||
54 | UI_CURSOR_ARROWDRAG, | ||
55 | UI_CURSOR_ARROWCOPY, // drag with copy | ||
56 | UI_CURSOR_ARROWDRAGMULTI, | ||
57 | UI_CURSOR_ARROWCOPYMULTI, // drag with copy | ||
58 | UI_CURSOR_NOLOCKED, | ||
59 | UI_CURSOR_ARROWLOCKED, | ||
60 | UI_CURSOR_GRABLOCKED, | ||
61 | UI_CURSOR_TOOLTRANSLATE, | ||
62 | UI_CURSOR_TOOLROTATE, | ||
63 | UI_CURSOR_TOOLSCALE, | ||
64 | UI_CURSOR_TOOLCAMERA, | ||
65 | UI_CURSOR_TOOLPAN, | ||
66 | UI_CURSOR_TOOLZOOMIN, | ||
67 | UI_CURSOR_TOOLPICKOBJECT3, | ||
68 | UI_CURSOR_TOOLSIT, | ||
69 | UI_CURSOR_TOOLBUY, | ||
70 | UI_CURSOR_TOOLPAY, | ||
71 | UI_CURSOR_TOOLOPEN, | ||
72 | UI_CURSOR_PIPETTE, | ||
73 | UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) | ||
74 | }; | ||
75 | |||
76 | class LLSplashScreen; | ||
77 | |||
78 | class LLWindow; | ||
79 | |||
80 | class LLWindowCallbacks | ||
81 | { | ||
82 | public: | ||
83 | virtual ~LLWindowCallbacks() {} | ||
84 | virtual BOOL handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated); | ||
85 | virtual BOOL handleTranslatedKeyUp(KEY key, MASK mask); | ||
86 | virtual void handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); | ||
87 | virtual BOOL handleUnicodeChar(llwchar uni_char, MASK mask); | ||
88 | |||
89 | virtual BOOL handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); | ||
90 | virtual BOOL handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); | ||
91 | virtual void handleMouseLeave(LLWindow *window); | ||
92 | // return TRUE to allow window to close, which will then cause handleQuit to be called | ||
93 | virtual BOOL handleCloseRequest(LLWindow *window); | ||
94 | // window is about to be destroyed, clean up your business | ||
95 | virtual void handleQuit(LLWindow *window); | ||
96 | virtual BOOL handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); | ||
97 | virtual BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); | ||
98 | virtual BOOL handleActivate(LLWindow *window, BOOL activated); | ||
99 | virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); | ||
100 | virtual void handleScrollWheel(LLWindow *window, S32 clicks); | ||
101 | virtual void handleResize(LLWindow *window, S32 width, S32 height); | ||
102 | virtual void handleFocus(LLWindow *window); | ||
103 | virtual void handleFocusLost(LLWindow *window); | ||
104 | virtual void handleMenuSelect(LLWindow *window, S32 menu_item); | ||
105 | virtual BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); | ||
106 | virtual BOOL handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); // double-click of left mouse button | ||
107 | virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while | ||
108 | virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while | ||
109 | virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); | ||
110 | }; | ||
111 | |||
112 | // Refer to llwindow_test in test/common/llwindow for usage example | ||
113 | |||
114 | class LLWindow | ||
115 | { | ||
116 | public: | ||
117 | struct LLWindowResolution | ||
118 | { | ||
119 | S32 mWidth; | ||
120 | S32 mHeight; | ||
121 | }; | ||
122 | enum ESwapMethod | ||
123 | { | ||
124 | SWAP_METHOD_UNDEFINED, | ||
125 | SWAP_METHOD_EXCHANGE, | ||
126 | SWAP_METHOD_COPY | ||
127 | }; | ||
128 | enum EFlags | ||
129 | { | ||
130 | // currently unused | ||
131 | }; | ||
132 | public: | ||
133 | virtual void show() = 0; | ||
134 | virtual void hide() = 0; | ||
135 | virtual void close() = 0; | ||
136 | virtual BOOL getVisible() = 0; | ||
137 | virtual BOOL getMinimized() = 0; | ||
138 | virtual BOOL getMaximized() = 0; | ||
139 | virtual BOOL maximize() = 0; | ||
140 | BOOL getFullscreen() { return mFullscreen; }; | ||
141 | virtual BOOL getPosition(LLCoordScreen *position) = 0; | ||
142 | virtual BOOL getSize(LLCoordScreen *size) = 0; | ||
143 | virtual BOOL getSize(LLCoordWindow *size) = 0; | ||
144 | virtual BOOL setPosition(LLCoordScreen position) = 0; | ||
145 | virtual BOOL setSize(LLCoordScreen size) = 0; | ||
146 | virtual BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) = 0; | ||
147 | virtual BOOL setCursorPosition(LLCoordWindow position) = 0; | ||
148 | virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; | ||
149 | virtual void showCursor() = 0; | ||
150 | virtual void hideCursor() = 0; | ||
151 | virtual BOOL isCursorHidden() = 0; | ||
152 | virtual void showCursorFromMouseMove() = 0; | ||
153 | virtual void hideCursorUntilMouseMove() = 0; | ||
154 | |||
155 | // These two functions create a way to make a busy cursor instead | ||
156 | // of an arrow when someone's busy doing something. Draw an | ||
157 | // arrow/hour if busycount > 0. | ||
158 | virtual void incBusyCount(); | ||
159 | virtual void decBusyCount(); | ||
160 | virtual void resetBusyCount() { mBusyCount = 0; } | ||
161 | virtual S32 getBusyCount() const { return mBusyCount; } | ||
162 | |||
163 | // Sets cursor, may set to arrow+hourglass | ||
164 | virtual void setCursor(ECursorType cursor) = 0; | ||
165 | virtual ECursorType getCursor() const { return mCurrentCursor; } | ||
166 | |||
167 | virtual void captureMouse() = 0; | ||
168 | virtual void releaseMouse() = 0; | ||
169 | virtual void setMouseClipping( BOOL b ) = 0; | ||
170 | virtual BOOL isClipboardTextAvailable() = 0; | ||
171 | virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; | ||
172 | virtual BOOL copyTextToClipboard(const LLWString &src) = 0; | ||
173 | virtual void flashIcon(F32 seconds) = 0; | ||
174 | virtual F32 getGamma() = 0; | ||
175 | virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma | ||
176 | virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) | ||
177 | virtual ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
178 | virtual void gatherInput() = 0; | ||
179 | virtual void delayInputProcessing() = 0; | ||
180 | virtual void swapBuffers() = 0; | ||
181 | virtual void bringToFront() = 0; | ||
182 | virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract | ||
183 | |||
184 | virtual S32 stat( const char* file_name, struct stat* stat_info ) = 0; | ||
185 | virtual BOOL sendEmail(const char* address,const char* subject,const char* body_text, const char* attachment=NULL, const char* attachment_displayed_name=NULL ) = 0; | ||
186 | |||
187 | |||
188 | // handy coordinate space conversion routines | ||
189 | // NB: screen to window and vice verse won't work on width/height coordinate pairs, | ||
190 | // as the conversion must take into account left AND right border widths, etc. | ||
191 | virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; | ||
192 | virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; | ||
193 | virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; | ||
194 | virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; | ||
195 | virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; | ||
196 | virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; | ||
197 | |||
198 | // query supported resolutions | ||
199 | virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; | ||
200 | virtual F32 getNativeAspectRatio() = 0; | ||
201 | virtual F32 getPixelAspectRatio() = 0; | ||
202 | virtual void setNativeAspectRatio(F32 aspect) = 0; | ||
203 | |||
204 | void setCallbacks(LLWindowCallbacks *callbacks); | ||
205 | |||
206 | virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) | ||
207 | virtual void afterDialog() {}; // undo whatever was done in beforeDialog() | ||
208 | |||
209 | // opens system default color picker | ||
210 | virtual BOOL dialog_color_picker (F32 *r, F32 *g, F32 *b) { return FALSE; }; | ||
211 | |||
212 | // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac) | ||
213 | virtual void *getPlatformWindow() = 0; | ||
214 | |||
215 | protected: | ||
216 | LLWindow(BOOL fullscreen, U32 flags); | ||
217 | virtual ~LLWindow() {} | ||
218 | virtual BOOL isValid() {return TRUE;} | ||
219 | virtual BOOL canDelete() {return TRUE;} | ||
220 | protected: | ||
221 | static LLWindowCallbacks sDefaultCallbacks; | ||
222 | |||
223 | protected: | ||
224 | LLWindowCallbacks* mCallbacks; | ||
225 | |||
226 | BOOL mPostQuit; // should this window post a quit message when destroyed? | ||
227 | BOOL mFullscreen; | ||
228 | S32 mFullscreenWidth; | ||
229 | S32 mFullscreenHeight; | ||
230 | S32 mFullscreenBits; | ||
231 | S32 mFullscreenRefresh; | ||
232 | LLWindowResolution* mSupportedResolutions; | ||
233 | S32 mNumSupportedResolutions; | ||
234 | ECursorType mCurrentCursor; | ||
235 | BOOL mCursorHidden; | ||
236 | S32 mBusyCount; // how deep is the "cursor busy" stack? | ||
237 | BOOL mIsMouseClipping; // Is this window currently clipping the mouse | ||
238 | ESwapMethod mSwapMethod; | ||
239 | BOOL mHideCursorPermanent; | ||
240 | U32 mFlags; | ||
241 | |||
242 | friend class LLWindowManager; | ||
243 | }; | ||
244 | |||
245 | |||
246 | // LLSplashScreen | ||
247 | // A simple, OS-specific splash screen that we can display | ||
248 | // while initializing the application and before creating a GL | ||
249 | // window | ||
250 | |||
251 | |||
252 | class LLSplashScreen | ||
253 | { | ||
254 | public: | ||
255 | LLSplashScreen() { }; | ||
256 | virtual ~LLSplashScreen() { }; | ||
257 | |||
258 | |||
259 | // Call to display the window. | ||
260 | static LLSplashScreen * create(); | ||
261 | static void show(); | ||
262 | static void hide(); | ||
263 | static void update(const char* string); | ||
264 | |||
265 | static bool isVisible(); | ||
266 | protected: | ||
267 | // These are overridden by the platform implementation | ||
268 | virtual void showImpl() = 0; | ||
269 | virtual void updateImpl(const char* string) = 0; | ||
270 | virtual void hideImpl() = 0; | ||
271 | |||
272 | static BOOL sVisible; | ||
273 | |||
274 | }; | ||
275 | |||
276 | // Platform-neutral for accessing the platform specific message box | ||
277 | S32 OSMessageBox(const char* text, const char* caption, U32 type); | ||
278 | const U32 OSMB_OK = 0; | ||
279 | const U32 OSMB_OKCANCEL = 1; | ||
280 | const U32 OSMB_YESNO = 2; | ||
281 | |||
282 | const S32 OSBTN_YES = 0; | ||
283 | const S32 OSBTN_NO = 1; | ||
284 | const S32 OSBTN_OK = 2; | ||
285 | const S32 OSBTN_CANCEL = 3; | ||
286 | |||
287 | // | ||
288 | // LLWindowManager | ||
289 | // Manages window creation and error checking | ||
290 | |||
291 | class LLWindowManager | ||
292 | { | ||
293 | public: | ||
294 | static LLWindow* createWindow( | ||
295 | char *title, | ||
296 | char *name, | ||
297 | LLCoordScreen upper_left = LLCoordScreen(10, 10), | ||
298 | LLCoordScreen size = LLCoordScreen(320, 240), | ||
299 | U32 flags = 0, | ||
300 | BOOL fullscreen = FALSE, | ||
301 | BOOL clearBg = FALSE, | ||
302 | BOOL disable_vsync = TRUE, | ||
303 | BOOL use_gl = TRUE, | ||
304 | BOOL ignore_pixel_depth = FALSE); | ||
305 | static LLWindow *createWindow( | ||
306 | char* title, char* name, S32 x, S32 y, S32 width, S32 height, | ||
307 | U32 flags = 0, | ||
308 | BOOL fullscreen = FALSE, | ||
309 | BOOL clearBg = FALSE, | ||
310 | BOOL disable_vsync = TRUE, | ||
311 | BOOL use_gl = TRUE, | ||
312 | BOOL ignore_pixel_depth = FALSE); | ||
313 | static BOOL destroyWindow(LLWindow* window); | ||
314 | static BOOL isWindowValid(LLWindow *window); | ||
315 | }; | ||
316 | |||
317 | // | ||
318 | // helper funcs | ||
319 | // | ||
320 | |||
321 | // Protocols, like "http" and "https" we support in URLs | ||
322 | extern const S32 gURLProtocolWhitelistCount; | ||
323 | extern const char* gURLProtocolWhitelist[]; | ||
324 | extern const char* gURLProtocolWhitelistHandler[]; | ||
325 | |||
326 | // Loads a URL with the user's default browser | ||
327 | void spawn_web_browser(const char* escaped_url); | ||
328 | |||
329 | // Opens a file with ShellExecute. Security risk! | ||
330 | void shell_open(const char* file_path); | ||
331 | |||
332 | void simpleEscapeString ( std::string& stringIn ); | ||
333 | |||
334 | #endif // _LL_window_h_ | ||
diff --git a/linden/indra/llwindow/llwindow.vcproj b/linden/indra/llwindow/llwindow.vcproj new file mode 100644 index 0000000..f2f4e32 --- /dev/null +++ b/linden/indra/llwindow/llwindow.vcproj | |||
@@ -0,0 +1,270 @@ | |||
1 | <?xml version="1.0" encoding="Windows-1252"?> | ||
2 | <VisualStudioProject | ||
3 | ProjectType="Visual C++" | ||
4 | Version="7.10" | ||
5 | Name="llwindow" | ||
6 | ProjectGUID="{B5B53617-416F-404A-BF10-22EBCCA0E4FB}" | ||
7 | Keyword="Win32Proj"> | ||
8 | <Platforms> | ||
9 | <Platform | ||
10 | Name="Win32"/> | ||
11 | </Platforms> | ||
12 | <Configurations> | ||
13 | <Configuration | ||
14 | Name="Debug|Win32" | ||
15 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
16 | IntermediateDirectory="Debug" | ||
17 | ConfigurationType="4" | ||
18 | CharacterSet="1"> | ||
19 | <Tool | ||
20 | Name="VCCLCompilerTool" | ||
21 | Optimization="0" | ||
22 | AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llxml;..\llvfs;..\llmessage;..\llscene;..\llimage;..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
23 | PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG" | ||
24 | MinimalRebuild="TRUE" | ||
25 | BasicRuntimeChecks="3" | ||
26 | RuntimeLibrary="1" | ||
27 | StructMemberAlignment="4" | ||
28 | ForceConformanceInForLoopScope="TRUE" | ||
29 | UsePrecompiledHeader="0" | ||
30 | WarningLevel="3" | ||
31 | WarnAsError="TRUE" | ||
32 | Detect64BitPortabilityProblems="FALSE" | ||
33 | DebugInformationFormat="4"/> | ||
34 | <Tool | ||
35 | Name="VCCustomBuildTool"/> | ||
36 | <Tool | ||
37 | Name="VCLibrarianTool" | ||
38 | OutputFile="$(OutDir)/llwindow.lib"/> | ||
39 | <Tool | ||
40 | Name="VCMIDLTool"/> | ||
41 | <Tool | ||
42 | Name="VCPostBuildEventTool"/> | ||
43 | <Tool | ||
44 | Name="VCPreBuildEventTool"/> | ||
45 | <Tool | ||
46 | Name="VCPreLinkEventTool"/> | ||
47 | <Tool | ||
48 | Name="VCResourceCompilerTool"/> | ||
49 | <Tool | ||
50 | Name="VCWebServiceProxyGeneratorTool"/> | ||
51 | <Tool | ||
52 | Name="VCXMLDataGeneratorTool"/> | ||
53 | <Tool | ||
54 | Name="VCManagedWrapperGeneratorTool"/> | ||
55 | <Tool | ||
56 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
57 | </Configuration> | ||
58 | <Configuration | ||
59 | Name="Release|Win32" | ||
60 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
61 | IntermediateDirectory="Release" | ||
62 | ConfigurationType="4" | ||
63 | CharacterSet="1"> | ||
64 | <Tool | ||
65 | Name="VCCLCompilerTool" | ||
66 | AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llxml;..\llvfs;..\llmessage;..\llscene;..\llimage;..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
67 | PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE" | ||
68 | RuntimeLibrary="0" | ||
69 | StructMemberAlignment="0" | ||
70 | ForceConformanceInForLoopScope="TRUE" | ||
71 | UsePrecompiledHeader="0" | ||
72 | WarningLevel="3" | ||
73 | WarnAsError="TRUE" | ||
74 | Detect64BitPortabilityProblems="FALSE" | ||
75 | DebugInformationFormat="3"/> | ||
76 | <Tool | ||
77 | Name="VCCustomBuildTool"/> | ||
78 | <Tool | ||
79 | Name="VCLibrarianTool" | ||
80 | OutputFile="$(OutDir)/llwindow.lib"/> | ||
81 | <Tool | ||
82 | Name="VCMIDLTool"/> | ||
83 | <Tool | ||
84 | Name="VCPostBuildEventTool"/> | ||
85 | <Tool | ||
86 | Name="VCPreBuildEventTool"/> | ||
87 | <Tool | ||
88 | Name="VCPreLinkEventTool"/> | ||
89 | <Tool | ||
90 | Name="VCResourceCompilerTool"/> | ||
91 | <Tool | ||
92 | Name="VCWebServiceProxyGeneratorTool"/> | ||
93 | <Tool | ||
94 | Name="VCXMLDataGeneratorTool"/> | ||
95 | <Tool | ||
96 | Name="VCManagedWrapperGeneratorTool"/> | ||
97 | <Tool | ||
98 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
99 | </Configuration> | ||
100 | <Configuration | ||
101 | Name="DebugMesaHeadless|Win32" | ||
102 | OutputDirectory="../lib_debug/i686-win32" | ||
103 | IntermediateDirectory="$(ConfigurationName)" | ||
104 | ConfigurationType="4" | ||
105 | CharacterSet="1"> | ||
106 | <Tool | ||
107 | Name="VCCLCompilerTool" | ||
108 | Optimization="0" | ||
109 | AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llxml;..\llvfs;..\llmessage;..\llscene;..\llimage;..\..\libraries\i686-win32\include;..\..\libraries\include\GLMESA;..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
110 | PreprocessorDefinitions="WIN32;_DEBUG;_LIB;LL_WINDOWS;LL_DEBUG;LL_MESA;LL_MESA_HEADLESS" | ||
111 | MinimalRebuild="TRUE" | ||
112 | BasicRuntimeChecks="3" | ||
113 | RuntimeLibrary="1" | ||
114 | StructMemberAlignment="4" | ||
115 | ForceConformanceInForLoopScope="TRUE" | ||
116 | UsePrecompiledHeader="0" | ||
117 | WarningLevel="3" | ||
118 | WarnAsError="TRUE" | ||
119 | Detect64BitPortabilityProblems="FALSE" | ||
120 | DebugInformationFormat="4"/> | ||
121 | <Tool | ||
122 | Name="VCCustomBuildTool"/> | ||
123 | <Tool | ||
124 | Name="VCLibrarianTool" | ||
125 | OutputFile="$(OutDir)/llwindow_mesaheadless.lib"/> | ||
126 | <Tool | ||
127 | Name="VCMIDLTool"/> | ||
128 | <Tool | ||
129 | Name="VCPostBuildEventTool"/> | ||
130 | <Tool | ||
131 | Name="VCPreBuildEventTool"/> | ||
132 | <Tool | ||
133 | Name="VCPreLinkEventTool"/> | ||
134 | <Tool | ||
135 | Name="VCResourceCompilerTool"/> | ||
136 | <Tool | ||
137 | Name="VCWebServiceProxyGeneratorTool"/> | ||
138 | <Tool | ||
139 | Name="VCXMLDataGeneratorTool"/> | ||
140 | <Tool | ||
141 | Name="VCManagedWrapperGeneratorTool"/> | ||
142 | <Tool | ||
143 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
144 | </Configuration> | ||
145 | <Configuration | ||
146 | Name="ReleaseNoOpt|Win32" | ||
147 | OutputDirectory="../lib_$(ConfigurationName)/i686-win32" | ||
148 | IntermediateDirectory="$(ConfigurationName)" | ||
149 | ConfigurationType="4" | ||
150 | CharacterSet="1"> | ||
151 | <Tool | ||
152 | Name="VCCLCompilerTool" | ||
153 | Optimization="0" | ||
154 | AdditionalIncludeDirectories="..\llcommon;..\llmath;..\llxml;..\llvfs;..\llmessage;..\llscene;..\llimage;..\..\libraries\i686-win32\include;..\..\libraries\include\" | ||
155 | PreprocessorDefinitions="WIN32;NDEBUG;_LIB;LL_WINDOWS;LL_RELEASE" | ||
156 | RuntimeLibrary="0" | ||
157 | StructMemberAlignment="0" | ||
158 | ForceConformanceInForLoopScope="TRUE" | ||
159 | UsePrecompiledHeader="0" | ||
160 | WarningLevel="3" | ||
161 | WarnAsError="TRUE" | ||
162 | Detect64BitPortabilityProblems="FALSE" | ||
163 | DebugInformationFormat="3"/> | ||
164 | <Tool | ||
165 | Name="VCCustomBuildTool"/> | ||
166 | <Tool | ||
167 | Name="VCLibrarianTool" | ||
168 | OutputFile="$(OutDir)/llwindow.lib"/> | ||
169 | <Tool | ||
170 | Name="VCMIDLTool"/> | ||
171 | <Tool | ||
172 | Name="VCPostBuildEventTool"/> | ||
173 | <Tool | ||
174 | Name="VCPreBuildEventTool"/> | ||
175 | <Tool | ||
176 | Name="VCPreLinkEventTool"/> | ||
177 | <Tool | ||
178 | Name="VCResourceCompilerTool"/> | ||
179 | <Tool | ||
180 | Name="VCWebServiceProxyGeneratorTool"/> | ||
181 | <Tool | ||
182 | Name="VCXMLDataGeneratorTool"/> | ||
183 | <Tool | ||
184 | Name="VCManagedWrapperGeneratorTool"/> | ||
185 | <Tool | ||
186 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
187 | </Configuration> | ||
188 | </Configurations> | ||
189 | <References> | ||
190 | </References> | ||
191 | <Files> | ||
192 | <Filter | ||
193 | Name="Source Files" | ||
194 | Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||
195 | UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> | ||
196 | <File | ||
197 | RelativePath=".\lldxhardware.cpp"> | ||
198 | </File> | ||
199 | <File | ||
200 | RelativePath=".\llgl.cpp"> | ||
201 | </File> | ||
202 | <File | ||
203 | RelativePath=".\llkeyboard.cpp"> | ||
204 | </File> | ||
205 | <File | ||
206 | RelativePath=".\llkeyboardwin32.cpp"> | ||
207 | </File> | ||
208 | <File | ||
209 | RelativePath=".\llwindow.cpp"> | ||
210 | </File> | ||
211 | <File | ||
212 | RelativePath=".\llwindowheadless.cpp"> | ||
213 | </File> | ||
214 | <File | ||
215 | RelativePath=".\llwindowmesaheadless.cpp"> | ||
216 | </File> | ||
217 | <File | ||
218 | RelativePath=".\llwindowwin32.cpp"> | ||
219 | </File> | ||
220 | </Filter> | ||
221 | <Filter | ||
222 | Name="Header Files" | ||
223 | Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||
224 | UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> | ||
225 | <File | ||
226 | RelativePath=".\lldxhardware.h"> | ||
227 | </File> | ||
228 | <File | ||
229 | RelativePath=".\llgl.h"> | ||
230 | </File> | ||
231 | <File | ||
232 | RelativePath=".\llglheaders.h"> | ||
233 | </File> | ||
234 | <File | ||
235 | RelativePath=".\llglstates.h"> | ||
236 | </File> | ||
237 | <File | ||
238 | RelativePath=".\llgltypes.h"> | ||
239 | </File> | ||
240 | <File | ||
241 | RelativePath=".\llkeyboard.h"> | ||
242 | </File> | ||
243 | <File | ||
244 | RelativePath=".\llkeyboardwin32.h"> | ||
245 | </File> | ||
246 | <File | ||
247 | RelativePath=".\llmousehandler.h"> | ||
248 | </File> | ||
249 | <File | ||
250 | RelativePath=".\llwindow.h"> | ||
251 | </File> | ||
252 | <File | ||
253 | RelativePath=".\llwindowheadless.h"> | ||
254 | </File> | ||
255 | <File | ||
256 | RelativePath=".\llwindowmesaheadless.h"> | ||
257 | </File> | ||
258 | <File | ||
259 | RelativePath=".\llwindowwin32.h"> | ||
260 | </File> | ||
261 | </Filter> | ||
262 | <Filter | ||
263 | Name="Resource Files" | ||
264 | Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" | ||
265 | UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> | ||
266 | </Filter> | ||
267 | </Files> | ||
268 | <Globals> | ||
269 | </Globals> | ||
270 | </VisualStudioProject> | ||
diff --git a/linden/indra/llwindow/llwindowheadless.cpp b/linden/indra/llwindow/llwindowheadless.cpp new file mode 100644 index 0000000..821632d --- /dev/null +++ b/linden/indra/llwindow/llwindowheadless.cpp | |||
@@ -0,0 +1,51 @@ | |||
1 | /** | ||
2 | * @file llwindowheadless.cpp | ||
3 | * @brief Headless implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | #include "indra_constants.h" | ||
30 | |||
31 | #include "llwindowheadless.h" | ||
32 | |||
33 | // | ||
34 | // LLWindowHeadless | ||
35 | // | ||
36 | LLWindowHeadless::LLWindowHeadless(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
37 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
38 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) | ||
39 | : LLWindow(fullscreen, flags) | ||
40 | { | ||
41 | } | ||
42 | |||
43 | |||
44 | LLWindowHeadless::~LLWindowHeadless() | ||
45 | { | ||
46 | } | ||
47 | |||
48 | void LLWindowHeadless::swapBuffers() | ||
49 | { | ||
50 | } | ||
51 | |||
diff --git a/linden/indra/llwindow/llwindowheadless.h b/linden/indra/llwindow/llwindowheadless.h new file mode 100644 index 0000000..cc7fa06 --- /dev/null +++ b/linden/indra/llwindow/llwindowheadless.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /** | ||
2 | * @file llwindowheadless.h | ||
3 | * @brief Headless definition of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWHEADLESS_H | ||
29 | #define LL_LLWINDOWHEADLESS_H | ||
30 | |||
31 | #include "llwindow.h" | ||
32 | |||
33 | class LLWindowHeadless : public LLWindow | ||
34 | { | ||
35 | public: | ||
36 | /*virtual*/ void show() {}; | ||
37 | /*virtual*/ void hide() {}; | ||
38 | /*virtual*/ void close() {}; | ||
39 | /*virtual*/ BOOL getVisible() {return FALSE;}; | ||
40 | /*virtual*/ BOOL getMinimized() {return FALSE;}; | ||
41 | /*virtual*/ BOOL getMaximized() {return FALSE;}; | ||
42 | /*virtual*/ BOOL maximize() {return FALSE;}; | ||
43 | /*virtual*/ BOOL getFullscreen() {return FALSE;}; | ||
44 | /*virtual*/ BOOL getPosition(LLCoordScreen *position) {return FALSE;}; | ||
45 | /*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;}; | ||
46 | /*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;}; | ||
47 | /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; | ||
48 | /*virtual*/ BOOL setSize(LLCoordScreen size) {return FALSE;}; | ||
49 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) {return FALSE;}; | ||
50 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; | ||
51 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; | ||
52 | /*virtual*/ void showCursor() {}; | ||
53 | /*virtual*/ void hideCursor() {}; | ||
54 | /*virtual*/ void showCursorFromMouseMove() {}; | ||
55 | /*virtual*/ void hideCursorUntilMouseMove() {}; | ||
56 | /*virtual*/ BOOL isCursorHidden() {return FALSE;}; | ||
57 | /*virtual*/ void setCursor(ECursorType cursor) {}; | ||
58 | //virtual ECursorType getCursor() { return mCurrentCursor; }; | ||
59 | /*virtual*/ void captureMouse() {}; | ||
60 | /*virtual*/ void releaseMouse() {}; | ||
61 | /*virtual*/ void setMouseClipping( BOOL b ) {}; | ||
62 | /*virtual*/ BOOL isClipboardTextAvailable() {return FALSE; }; | ||
63 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) {return FALSE; }; | ||
64 | /*virtual*/ BOOL copyTextToClipboard(const LLWString &src) {return FALSE; }; | ||
65 | /*virtual*/ void flashIcon(F32 seconds) {}; | ||
66 | /*virtual*/ F32 getGamma() {return 1.0f; }; | ||
67 | /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma | ||
68 | /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) | ||
69 | //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
70 | /*virtual*/ void gatherInput() {}; | ||
71 | /*virtual*/ void delayInputProcessing() {}; | ||
72 | /*virtual*/ void swapBuffers(); | ||
73 | |||
74 | /*virtual*/ LLString getTempFileName() {return LLString(""); }; | ||
75 | /*virtual*/ void deleteFile( const char* file_name ) {}; | ||
76 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ) {return 0; }; | ||
77 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL) { return FALSE; }; | ||
78 | |||
79 | |||
80 | // handy coordinate space conversion routines | ||
81 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) { return FALSE; }; | ||
82 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) { return FALSE; }; | ||
83 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) { return FALSE; }; | ||
84 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) { return FALSE; }; | ||
85 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) { return FALSE; }; | ||
86 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) { return FALSE; }; | ||
87 | |||
88 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; | ||
89 | /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; | ||
90 | /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; | ||
91 | /*virtual*/ void setNativeAspectRatio(F32 ratio) {} | ||
92 | |||
93 | /*virtual*/ void *getPlatformWindow() { return 0; }; | ||
94 | /*virtual*/ void bringToFront() {}; | ||
95 | |||
96 | LLWindowHeadless(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
97 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
98 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); | ||
99 | virtual ~LLWindowHeadless(); | ||
100 | |||
101 | private: | ||
102 | }; | ||
103 | |||
104 | class LLSplashScreenHeadless : public LLSplashScreen | ||
105 | { | ||
106 | public: | ||
107 | LLSplashScreenHeadless() {}; | ||
108 | virtual ~LLSplashScreenHeadless() {}; | ||
109 | |||
110 | /*virtual*/ void showImpl() {}; | ||
111 | /*virtual*/ void updateImpl(const char* mesg) {}; | ||
112 | /*virtual*/ void hideImpl() {}; | ||
113 | |||
114 | }; | ||
115 | |||
116 | #endif //LL_LLWINDOWHEADLESS_H | ||
117 | |||
diff --git a/linden/indra/llwindow/llwindowlinux.cpp b/linden/indra/llwindow/llwindowlinux.cpp new file mode 100644 index 0000000..e266efc --- /dev/null +++ b/linden/indra/llwindow/llwindowlinux.cpp | |||
@@ -0,0 +1,57 @@ | |||
1 | /** | ||
2 | * @file llwindowlinux.cpp | ||
3 | * @brief Platform-dependent implementation of llwindow | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_LINUX | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "indra_constants.h" | ||
32 | |||
33 | #include "llwindowlinux.h" | ||
34 | #include "llgl.h" | ||
35 | #include "llglheaders.h" | ||
36 | |||
37 | // | ||
38 | // LLWindowLinux | ||
39 | // | ||
40 | LLWindowLinux::LLWindowLinux(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
41 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
42 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) | ||
43 | : LLWindow(fullscreen, flags) | ||
44 | { | ||
45 | llerrs << "Linux window not yet supported" << llendl; | ||
46 | } | ||
47 | |||
48 | |||
49 | LLWindowLinux::~LLWindowLinux() | ||
50 | { | ||
51 | } | ||
52 | |||
53 | void LLWindowLinux::swapBuffers() | ||
54 | { | ||
55 | } | ||
56 | |||
57 | #endif // LL_LINUX | ||
diff --git a/linden/indra/llwindow/llwindowlinux.h b/linden/indra/llwindow/llwindowlinux.h new file mode 100644 index 0000000..9550cdd --- /dev/null +++ b/linden/indra/llwindow/llwindowlinux.h | |||
@@ -0,0 +1,115 @@ | |||
1 | /** | ||
2 | * @file llwindowlinux.h | ||
3 | * @brief Linux implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWWIN32_H | ||
29 | #define LL_LLWINDOWWIN32_H | ||
30 | |||
31 | #include "llwindow.h" | ||
32 | |||
33 | class LLWindowLinux : public LLWindow | ||
34 | { | ||
35 | public: | ||
36 | /*virtual*/ void show() {}; | ||
37 | /*virtual*/ void hide() {}; | ||
38 | /*virtual*/ void close() {}; | ||
39 | /*virtual*/ BOOL getVisible() {return FALSE;}; | ||
40 | /*virtual*/ BOOL getMinimized() {return FALSE;}; | ||
41 | /*virtual*/ BOOL getMaximized() {return FALSE;}; | ||
42 | /*virtual*/ BOOL maximize() {return FALSE;}; | ||
43 | /*virtual*/ BOOL getFullscreen() {return FALSE;}; | ||
44 | /*virtual*/ BOOL getPosition(LLCoordScreen *position) {return FALSE;}; | ||
45 | /*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;}; | ||
46 | /*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;}; | ||
47 | /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; | ||
48 | /*virtual*/ BOOL setSize(LLCoordScreen size) {return FALSE;}; | ||
49 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) {return FALSE;}; | ||
50 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; | ||
51 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; | ||
52 | /*virtual*/ void showCursor() {}; | ||
53 | /*virtual*/ void hideCursor() {}; | ||
54 | /*virtual*/ void showCursorFromMouseMove() {}; | ||
55 | /*virtual*/ void hideCursorUntilMouseMove() {}; | ||
56 | /*virtual*/ BOOL isCursorHidden() {return FALSE;}; | ||
57 | /*virtual*/ void setCursor(ECursorType cursor) {}; | ||
58 | //virtual ECursorType getCursor() { return mCurrentCursor; }; | ||
59 | /*virtual*/ void captureMouse() {}; | ||
60 | /*virtual*/ void releaseMouse() {}; | ||
61 | /*virtual*/ void setMouseClipping( BOOL b ) {}; | ||
62 | /*virtual*/ BOOL isClipboardTextAvailable() {return FALSE; }; | ||
63 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) {return FALSE; }; | ||
64 | /*virtual*/ BOOL copyTextToClipboard(const LLWString &src) {return FALSE; }; | ||
65 | /*virtual*/ void flashIcon(F32 seconds) {}; | ||
66 | /*virtual*/ F32 getGamma() {return 1.0f; }; | ||
67 | /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma | ||
68 | /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) | ||
69 | //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
70 | /*virtual*/ void gatherInput() {}; | ||
71 | /*virtual*/ void delayInputProcessing() {}; | ||
72 | /*virtual*/ void swapBuffers(); | ||
73 | |||
74 | /*virtual*/ LLString getTempFileName() {return LLString(""); }; | ||
75 | /*virtual*/ void deleteFile( const char* file_name ) {}; | ||
76 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ) {return 0; }; | ||
77 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL) { return FALSE; }; | ||
78 | |||
79 | |||
80 | // handy coordinate space conversion routines | ||
81 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) { return FALSE; }; | ||
82 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) { return FALSE; }; | ||
83 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) { return FALSE; }; | ||
84 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) { return FALSE; }; | ||
85 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) { return FALSE; }; | ||
86 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) { return FALSE; }; | ||
87 | |||
88 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; | ||
89 | /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; | ||
90 | /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; | ||
91 | /*virtual*/ void setNativeAspectRatio(F32 ratio) {} | ||
92 | |||
93 | //virtual BOOL dialog_color_picker (F32 *r, F32 *g, F32 *b ); | ||
94 | |||
95 | /*virtual*/ void *getPlatformWindow() { return NULL; } | ||
96 | |||
97 | LLWindowLinux(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
98 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
99 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); | ||
100 | ~LLWindowLinux(); | ||
101 | }; | ||
102 | |||
103 | class LLSplashScreenLinux : public LLSplashScreen | ||
104 | { | ||
105 | public: | ||
106 | LLSplashScreenLinux() {}; | ||
107 | virtual ~LLSplashScreenLinux() {}; | ||
108 | |||
109 | /*virtual*/ void showImpl() {}; | ||
110 | /*virtual*/ void updateImpl(const char* mesg) {}; | ||
111 | /*virtual*/ void hideImpl() {}; | ||
112 | |||
113 | }; | ||
114 | |||
115 | #endif //LL_LLWINDOWWIN32_H | ||
diff --git a/linden/indra/llwindow/llwindowmacosx-objc.h b/linden/indra/llwindow/llwindowmacosx-objc.h new file mode 100644 index 0000000..d055729 --- /dev/null +++ b/linden/indra/llwindow/llwindowmacosx-objc.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /** | ||
2 | * @file llwindowmacosx-objc.h | ||
3 | * @brief Prototypes for functions shared between llwindowmacosx.cpp | ||
4 | * and llwindowmacosx-objc.mm. | ||
5 | * | ||
6 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | |||
30 | // This will actually hold an NSCursor*, but that type is only available in objective C. | ||
31 | typedef void *CursorRef; | ||
32 | |||
33 | /* Defined in llwindowmacosx-objc.mm: */ | ||
34 | void setupCocoa(); | ||
35 | CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY); | ||
36 | OSErr releaseImageCursor(CursorRef ref); | ||
37 | OSErr setImageCursor(CursorRef ref); | ||
38 | |||
diff --git a/linden/indra/llwindow/llwindowmacosx-objc.mm b/linden/indra/llwindow/llwindowmacosx-objc.mm new file mode 100644 index 0000000..bde3841 --- /dev/null +++ b/linden/indra/llwindow/llwindowmacosx-objc.mm | |||
@@ -0,0 +1,106 @@ | |||
1 | /** | ||
2 | * @file llwindowmacosx-objc.mm | ||
3 | * @brief Definition of functions shared between llwindowmacosx.cpp | ||
4 | * and llwindowmacosx-objc.mm. | ||
5 | * | ||
6 | * Copyright (c) 2006-2007, Linden Research, Inc. | ||
7 | * | ||
8 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
9 | * to you under the terms of the GNU General Public License, version 2.0 | ||
10 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
11 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
12 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
13 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
14 | * | ||
15 | * There are special exceptions to the terms and conditions of the GPL as | ||
16 | * it is applied to this Source Code. View the full text of the exception | ||
17 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
18 | * online at http://secondlife.com/developers/opensource/flossexception | ||
19 | * | ||
20 | * By copying, modifying or distributing this software, you acknowledge | ||
21 | * that you have read and understood your obligations described above, | ||
22 | * and agree to abide by those obligations. | ||
23 | * | ||
24 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
25 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
26 | * COMPLETENESS OR PERFORMANCE. | ||
27 | */ | ||
28 | |||
29 | #include <AppKit/AppKit.h> | ||
30 | |||
31 | /* | ||
32 | * These functions are broken out into a separate file because the | ||
33 | * objective-C typedef for 'BOOL' conflicts with the one in | ||
34 | * llcommon/stdtypes.h. This makes it impossible to use the standard | ||
35 | * linden headers with any objective-C++ source. | ||
36 | */ | ||
37 | |||
38 | #include "llwindowmacosx-objc.h" | ||
39 | |||
40 | void setupCocoa() | ||
41 | { | ||
42 | static bool inited = false; | ||
43 | |||
44 | if(!inited) | ||
45 | { | ||
46 | // This is a bit of voodoo taken from the Apple sample code "CarbonCocoa_PictureCursor": | ||
47 | // http://developer.apple.com/samplecode/CarbonCocoa_PictureCursor/index.html | ||
48 | |||
49 | // Needed for Carbon based applications which call into Cocoa | ||
50 | NSApplicationLoad(); | ||
51 | |||
52 | // Must first call [[[NSWindow alloc] init] release] to get the NSWindow machinery set up so that NSCursor can use a window to cache the cursor image | ||
53 | [[[NSWindow alloc] init] release]; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY) | ||
58 | { | ||
59 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | ||
60 | |||
61 | // extra retain on the NSCursor since we want it to live for the lifetime of the app. | ||
62 | NSCursor *cursor = | ||
63 | [[[NSCursor alloc] | ||
64 | initWithImage: | ||
65 | [[[NSImage alloc] initWithContentsOfFile: | ||
66 | [NSString stringWithFormat:@"%s", fullpath] | ||
67 | ]autorelease] | ||
68 | hotSpot:NSMakePoint(hotspotX, hotspotY) | ||
69 | ]retain]; | ||
70 | |||
71 | [pool release]; | ||
72 | |||
73 | return (CursorRef)cursor; | ||
74 | } | ||
75 | |||
76 | // This is currently unused, since we want all our cursors to persist for the life of the app, but I've included it for completeness. | ||
77 | OSErr releaseImageCursor(CursorRef ref) | ||
78 | { | ||
79 | if( ref != NULL ) | ||
80 | { | ||
81 | NSCursor *cursor = (NSCursor*)ref; | ||
82 | [cursor release]; | ||
83 | } | ||
84 | else | ||
85 | { | ||
86 | return paramErr; | ||
87 | } | ||
88 | |||
89 | return noErr; | ||
90 | } | ||
91 | |||
92 | OSErr setImageCursor(CursorRef ref) | ||
93 | { | ||
94 | if( ref != NULL ) | ||
95 | { | ||
96 | NSCursor *cursor = (NSCursor*)ref; | ||
97 | [cursor set]; | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | return paramErr; | ||
102 | } | ||
103 | |||
104 | return noErr; | ||
105 | } | ||
106 | |||
diff --git a/linden/indra/llwindow/llwindowmacosx.cpp b/linden/indra/llwindow/llwindowmacosx.cpp new file mode 100644 index 0000000..d990bb5 --- /dev/null +++ b/linden/indra/llwindow/llwindowmacosx.cpp | |||
@@ -0,0 +1,2923 @@ | |||
1 | /** | ||
2 | * @file llwindowmacosx.cpp | ||
3 | * @brief Platform-dependent implementation of llwindow | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_DARWIN | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | |||
32 | #include <Carbon/Carbon.h> | ||
33 | |||
34 | #include "llwindowmacosx.h" | ||
35 | #include "llkeyboardmacosx.h" | ||
36 | #include "llerror.h" | ||
37 | #include "llgl.h" | ||
38 | #include "llstring.h" | ||
39 | #include "lldir.h" | ||
40 | |||
41 | #include "llglheaders.h" | ||
42 | |||
43 | #include "indra_constants.h" | ||
44 | |||
45 | #include "llwindowmacosx-objc.h" | ||
46 | |||
47 | extern BOOL gDebugWindowProc; | ||
48 | |||
49 | // culled from winuser.h | ||
50 | //const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ | ||
51 | // On the Mac, the scroll wheel reports a delta of 1 for each detent. | ||
52 | // There's also acceleration for faster scrolling, based on a slider in the system preferences. | ||
53 | const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */ | ||
54 | const S32 BITS_PER_PIXEL = 32; | ||
55 | const S32 MAX_NUM_RESOLUTIONS = 32; | ||
56 | |||
57 | |||
58 | // | ||
59 | // LLWindowMacOSX | ||
60 | // | ||
61 | |||
62 | // Cross-platform bits: | ||
63 | |||
64 | void show_window_creation_error(const char* title) | ||
65 | { | ||
66 | llwarns << title << llendl; | ||
67 | shell_open( "help/window_creation_error.html"); | ||
68 | /* | ||
69 | OSMessageBox( | ||
70 | "Second Life is unable to run because it can't set up your display.\n" | ||
71 | "We need to be able to make a 32-bit color window at 1024x768, with\n" | ||
72 | "an 8 bit alpha channel.\n" | ||
73 | "\n" | ||
74 | "First, be sure your monitor is set to True Color (32-bit) in\n" | ||
75 | "Start -> Control Panels -> Display -> Settings.\n" | ||
76 | "\n" | ||
77 | "Otherwise, this may be due to video card driver issues.\n" | ||
78 | "Please make sure you have the latest video card drivers installed.\n" | ||
79 | "ATI drivers are available at http://www.ati.com/\n" | ||
80 | "nVidia drivers are available at http://www.nvidia.com/\n" | ||
81 | "\n" | ||
82 | "If you continue to receive this message, contact customer service.", | ||
83 | title, | ||
84 | OSMB_OK); | ||
85 | */ | ||
86 | } | ||
87 | |||
88 | BOOL check_for_card(const char* RENDERER, const char* bad_card) | ||
89 | { | ||
90 | if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) | ||
91 | { | ||
92 | char buffer[1024]; | ||
93 | sprintf(buffer, | ||
94 | "Your video card appears to be a %s, which Second Life does not support.\n" | ||
95 | "\n" | ||
96 | "Second Life requires a video card with 32 Mb of memory or more, as well as\n" | ||
97 | "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" | ||
98 | "and ATI Radeon 8500 or better.\n" | ||
99 | "\n" | ||
100 | "If you own a supported card and continue to receive this message, try \n" | ||
101 | "updating to the latest video card drivers. Otherwise look in the\n" | ||
102 | "secondlife.com support section or e-mail technical support\n" | ||
103 | "\n" | ||
104 | "You can try to run Second Life, but it will probably crash or run\n" | ||
105 | "very slowly. Try anyway?", | ||
106 | bad_card); | ||
107 | S32 button = OSMessageBox(buffer, "Unsupported video card", OSMB_YESNO); | ||
108 | if (OSBTN_YES == button) | ||
109 | { | ||
110 | return FALSE; | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | return TRUE; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | return FALSE; | ||
119 | } | ||
120 | |||
121 | |||
122 | |||
123 | // Switch to determine whether we capture all displays, or just the main one. | ||
124 | // We may want to base this on the setting of _DEBUG... | ||
125 | |||
126 | #define CAPTURE_ALL_DISPLAYS 0 | ||
127 | static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); | ||
128 | static long getDictLong (CFDictionaryRef refDict, CFStringRef key); | ||
129 | |||
130 | |||
131 | |||
132 | |||
133 | // CarbonEvents we're interested in. | ||
134 | static EventTypeSpec WindowHandlerEventList[] = | ||
135 | { | ||
136 | // Window-related events | ||
137 | // { kEventClassWindow, kEventWindowCollapsing }, | ||
138 | // { kEventClassWindow, kEventWindowCollapsed }, | ||
139 | // { kEventClassWindow, kEventWindowShown }, | ||
140 | { kEventClassWindow, kEventWindowActivated }, | ||
141 | { kEventClassWindow, kEventWindowDeactivated }, | ||
142 | { kEventClassWindow, kEventWindowShown }, | ||
143 | { kEventClassWindow, kEventWindowHidden }, | ||
144 | { kEventClassWindow, kEventWindowCollapsed }, | ||
145 | { kEventClassWindow, kEventWindowExpanded }, | ||
146 | { kEventClassWindow, kEventWindowGetClickActivation }, | ||
147 | { kEventClassWindow, kEventWindowClose }, | ||
148 | { kEventClassWindow, kEventWindowBoundsChanging }, | ||
149 | { kEventClassWindow, kEventWindowBoundsChanged }, | ||
150 | // { kEventClassWindow, kEventWindowZoomed }, | ||
151 | // { kEventClassWindow, kEventWindowDrawContent }, | ||
152 | |||
153 | // Mouse events | ||
154 | { kEventClassMouse, kEventMouseDown }, | ||
155 | { kEventClassMouse, kEventMouseUp }, | ||
156 | { kEventClassMouse, kEventMouseDragged }, | ||
157 | { kEventClassMouse, kEventMouseWheelMoved }, | ||
158 | { kEventClassMouse, kEventMouseMoved }, | ||
159 | |||
160 | // Keyboard events | ||
161 | // No longer handle raw key down events directly. | ||
162 | // When text input events come in, extract the raw key events from them and process at that point. | ||
163 | // This allows input methods to eat keystrokes the way they're supposed to. | ||
164 | // { kEventClassKeyboard, kEventRawKeyDown }, | ||
165 | // { kEventClassKeyboard, kEventRawKeyRepeat }, | ||
166 | { kEventClassKeyboard, kEventRawKeyUp }, | ||
167 | { kEventClassKeyboard, kEventRawKeyModifiersChanged }, | ||
168 | |||
169 | // Text input events | ||
170 | { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } | ||
171 | |||
172 | }; | ||
173 | |||
174 | static EventTypeSpec GlobalHandlerEventList[] = | ||
175 | { | ||
176 | // Mouse events | ||
177 | { kEventClassMouse, kEventMouseDown }, | ||
178 | { kEventClassMouse, kEventMouseUp }, | ||
179 | { kEventClassMouse, kEventMouseDragged }, | ||
180 | { kEventClassMouse, kEventMouseWheelMoved }, | ||
181 | { kEventClassMouse, kEventMouseMoved }, | ||
182 | |||
183 | // Keyboard events | ||
184 | // No longer handle raw key down events directly. | ||
185 | // When text input events come in, extract the raw key events from them and process at that point. | ||
186 | // This allows input methods to eat keystrokes the way they're supposed to. | ||
187 | // { kEventClassKeyboard, kEventRawKeyDown }, | ||
188 | // { kEventClassKeyboard, kEventRawKeyRepeat }, | ||
189 | { kEventClassKeyboard, kEventRawKeyUp }, | ||
190 | { kEventClassKeyboard, kEventRawKeyModifiersChanged }, | ||
191 | |||
192 | // Text input events | ||
193 | { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } | ||
194 | }; | ||
195 | |||
196 | static EventTypeSpec CommandHandlerEventList[] = | ||
197 | { | ||
198 | { kEventClassCommand, kEventCommandProcess } | ||
199 | }; | ||
200 | |||
201 | // MBW -- HACK ALERT | ||
202 | // On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. | ||
203 | // The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these | ||
204 | // require a pointer to the LLWindowMacOSX object. Stash it here and maintain in the constructor and destructor. | ||
205 | // This assumes that there will be only one object of this class at any time. Hopefully this is true. | ||
206 | static LLWindowMacOSX *gWindowImplementation = NULL; | ||
207 | |||
208 | |||
209 | |||
210 | LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width, | ||
211 | S32 height, U32 flags, | ||
212 | BOOL fullscreen, BOOL clearBg, | ||
213 | BOOL disable_vsync, BOOL use_gl, | ||
214 | BOOL ignore_pixel_depth) | ||
215 | : LLWindow(fullscreen, flags) | ||
216 | { | ||
217 | // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). | ||
218 | setupCocoa(); | ||
219 | |||
220 | // Initialize the keyboard | ||
221 | gKeyboard = new LLKeyboardMacOSX(); | ||
222 | |||
223 | // Ignore use_gl for now, only used for drones on PC | ||
224 | mWindow = NULL; | ||
225 | mContext = NULL; | ||
226 | mPixelFormat = NULL; | ||
227 | mDisplay = CGMainDisplayID(); | ||
228 | mOldDisplayMode = NULL; | ||
229 | mTimer = NULL; | ||
230 | mSimulatedRightClick = FALSE; | ||
231 | mLastModifiers = 0; | ||
232 | mHandsOffEvents = FALSE; | ||
233 | mCursorDecoupled = FALSE; | ||
234 | mCursorLastEventDeltaX = 0; | ||
235 | mCursorLastEventDeltaY = 0; | ||
236 | mCursorIgnoreNextDelta = FALSE; | ||
237 | mNeedsResize = FALSE; | ||
238 | mOverrideAspectRatio = 0.f; | ||
239 | mMinimized = FALSE; | ||
240 | |||
241 | // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state. | ||
242 | // Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state. | ||
243 | mBounceTimer.stop(); | ||
244 | |||
245 | // Get the original aspect ratio of the main device. | ||
246 | mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); | ||
247 | |||
248 | // Stash the window title | ||
249 | strcpy((char*)mWindowTitle + 1, title); | ||
250 | mWindowTitle[0] = strlen(title); | ||
251 | |||
252 | mEventHandlerUPP = NewEventHandlerUPP(staticEventHandler); | ||
253 | mGlobalHandlerRef = NULL; | ||
254 | mWindowHandlerRef = NULL; | ||
255 | |||
256 | // We're not clipping yet | ||
257 | SetRect( &mOldMouseClip, 0, 0, 0, 0 ); | ||
258 | |||
259 | // Set up global event handlers (the fullscreen case needs this) | ||
260 | InstallStandardEventHandler(GetApplicationEventTarget()); | ||
261 | |||
262 | // Stash an object pointer for OSMessageBox() | ||
263 | gWindowImplementation = this; | ||
264 | |||
265 | // Create the GL context and set it up for windowed or fullscreen, as appropriate. | ||
266 | if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) | ||
267 | { | ||
268 | if(mWindow != NULL) | ||
269 | { | ||
270 | // MBW -- XXX -- I think we can now do this here? | ||
271 | // Constrain the window to the screen it's mostly on, resizing if necessary. | ||
272 | ConstrainWindowToScreen( | ||
273 | mWindow, | ||
274 | kWindowStructureRgn, | ||
275 | kWindowConstrainMayResize | | ||
276 | // kWindowConstrainStandardOptions | | ||
277 | 0, | ||
278 | NULL, | ||
279 | NULL); | ||
280 | |||
281 | MacShowWindow(mWindow); | ||
282 | BringToFront(mWindow); | ||
283 | } | ||
284 | |||
285 | if (!gGLManager.initGL()) | ||
286 | { | ||
287 | setupFailure( | ||
288 | "Second Life is unable to run because your video card drivers\n" | ||
289 | "are out of date or unsupported. Please make sure you have\n" | ||
290 | "the latest video card drivers installed.\n" | ||
291 | "If you continue to receive this message, contact customer service.", | ||
292 | "Error", | ||
293 | OSMB_OK); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | //start with arrow cursor | ||
298 | initCursors(); | ||
299 | setCursor( UI_CURSOR_ARROW ); | ||
300 | } | ||
301 | |||
302 | stop_glerror(); | ||
303 | } | ||
304 | |||
305 | BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) | ||
306 | { | ||
307 | OSStatus err; | ||
308 | BOOL glNeedsInit = FALSE; | ||
309 | |||
310 | if(mGlobalHandlerRef == NULL) | ||
311 | { | ||
312 | InstallApplicationEventHandler(mEventHandlerUPP, GetEventTypeCount (CommandHandlerEventList), CommandHandlerEventList, (void*)this, &mGlobalHandlerRef); | ||
313 | } | ||
314 | |||
315 | mFullscreen = fullscreen; | ||
316 | |||
317 | if (mFullscreen && (mOldDisplayMode == NULL)) | ||
318 | { | ||
319 | llinfos << "createContext: setting up fullscreen " << width << "x" << height << llendl; | ||
320 | |||
321 | // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays. Plan accordingly. | ||
322 | double refresh = getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate); | ||
323 | |||
324 | // If the requested width or height is 0, find the best default for the monitor. | ||
325 | if((width == 0) || (height == 0)) | ||
326 | { | ||
327 | // Scan through the list of modes, looking for one which has: | ||
328 | // height between 700 and 800 | ||
329 | // aspect ratio closest to the user's original mode | ||
330 | S32 resolutionCount = 0; | ||
331 | LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); | ||
332 | |||
333 | if(resolutionList != NULL) | ||
334 | { | ||
335 | F32 closestAspect = 0; | ||
336 | U32 closestHeight = 0; | ||
337 | U32 closestWidth = 0; | ||
338 | int i; | ||
339 | |||
340 | llinfos << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << llendl; | ||
341 | |||
342 | for(i=0; i < resolutionCount; i++) | ||
343 | { | ||
344 | F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; | ||
345 | |||
346 | llinfos << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << llendl; | ||
347 | |||
348 | if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && | ||
349 | (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) | ||
350 | { | ||
351 | llinfos << " (new closest mode) " << llendl; | ||
352 | |||
353 | // This is the closest mode we've seen yet. | ||
354 | closestWidth = resolutionList[i].mWidth; | ||
355 | closestHeight = resolutionList[i].mHeight; | ||
356 | closestAspect = aspect; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | width = closestWidth; | ||
361 | height = closestHeight; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | if((width == 0) || (height == 0)) | ||
366 | { | ||
367 | // Mode search failed for some reason. Use the old-school default. | ||
368 | width = 1024; | ||
369 | height = 768; | ||
370 | } | ||
371 | |||
372 | if (true) | ||
373 | { | ||
374 | // Fullscreen support | ||
375 | CFDictionaryRef refDisplayMode = 0; | ||
376 | boolean_t exactMatch = false; | ||
377 | |||
378 | #if CAPTURE_ALL_DISPLAYS | ||
379 | // Capture all displays (may want to do this for final build) | ||
380 | CGCaptureAllDisplays (); | ||
381 | #else | ||
382 | // Capture only the main display (useful for debugging) | ||
383 | CGDisplayCapture (mDisplay); | ||
384 | #endif | ||
385 | |||
386 | // Switch the display to the desired resolution and refresh | ||
387 | refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate( | ||
388 | mDisplay, | ||
389 | BITS_PER_PIXEL, | ||
390 | width, | ||
391 | height, | ||
392 | refresh, | ||
393 | &exactMatch); | ||
394 | |||
395 | if (refDisplayMode) | ||
396 | { | ||
397 | llinfos << "createContext: switching display resolution" << llendl; | ||
398 | mOldDisplayMode = CGDisplayCurrentMode (mDisplay); | ||
399 | CGDisplaySwitchToMode (mDisplay, refDisplayMode); | ||
400 | // CFRelease(refDisplayMode); | ||
401 | |||
402 | AddEventTypesToHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList); | ||
403 | } | ||
404 | |||
405 | |||
406 | mFullscreen = TRUE; | ||
407 | mFullscreenWidth = CGDisplayPixelsWide(mDisplay); | ||
408 | mFullscreenHeight = CGDisplayPixelsHigh(mDisplay); | ||
409 | mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); | ||
410 | mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); | ||
411 | |||
412 | llinfos << "Running at " << mFullscreenWidth | ||
413 | << "x" << mFullscreenHeight | ||
414 | << "x" << mFullscreenBits | ||
415 | << " @ " << mFullscreenRefresh | ||
416 | << llendl; | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | // No fullscreen support | ||
421 | mFullscreen = FALSE; | ||
422 | mFullscreenWidth = -1; | ||
423 | mFullscreenHeight = -1; | ||
424 | mFullscreenBits = -1; | ||
425 | mFullscreenRefresh = -1; | ||
426 | |||
427 | char error[256]; | ||
428 | sprintf(error, "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); | ||
429 | OSMessageBox(error, "Error", OSMB_OK); | ||
430 | } | ||
431 | } | ||
432 | |||
433 | if(!mFullscreen && (mWindow == NULL)) | ||
434 | { | ||
435 | Rect window_rect; | ||
436 | //int displayWidth = CGDisplayPixelsWide(mDisplay); | ||
437 | //int displayHeight = CGDisplayPixelsHigh(mDisplay); | ||
438 | //const int menuBarPlusTitleBar = 44; // Ugly magic number. | ||
439 | |||
440 | llinfos << "createContext: creating window" << llendl; | ||
441 | |||
442 | window_rect.left = (long) x; | ||
443 | window_rect.right = (long) x + width; | ||
444 | window_rect.top = (long) y; | ||
445 | window_rect.bottom = (long) y + height; | ||
446 | |||
447 | //----------------------------------------------------------------------- | ||
448 | // Create the window | ||
449 | //----------------------------------------------------------------------- | ||
450 | mWindow = NewCWindow( | ||
451 | NULL, | ||
452 | &window_rect, | ||
453 | mWindowTitle, | ||
454 | false, // Create the window invisible. Whoever calls createContext() should show it after any moving/resizing. | ||
455 | // noGrowDocProc, // Window with no grow box and no zoom box | ||
456 | zoomDocProc, // Window with a grow box and a zoom box | ||
457 | // zoomNoGrow, // Window with a zoom box but no grow box | ||
458 | kFirstWindowOfClass, | ||
459 | true, | ||
460 | (long)this); | ||
461 | |||
462 | |||
463 | if (!mWindow) | ||
464 | { | ||
465 | setupFailure("Window creation error", "Error", OSMB_OK); | ||
466 | return FALSE; | ||
467 | } | ||
468 | |||
469 | // Turn on live resize. | ||
470 | // For this to work correctly, we need to be able to call LLViewerWindow::draw from | ||
471 | // the event handler for kEventWindowBoundsChanged. It's not clear that we have access from here. | ||
472 | // err = ChangeWindowAttributes(mWindow, kWindowLiveResizeAttribute, 0); | ||
473 | |||
474 | // Set up window event handlers (some window-related events ONLY go to window handlers.) | ||
475 | InstallStandardEventHandler(GetWindowEventTarget(mWindow)); | ||
476 | InstallWindowEventHandler (mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler | ||
477 | |||
478 | } | ||
479 | |||
480 | if(mContext == NULL) | ||
481 | { | ||
482 | AGLRendererInfo rendererInfo = NULL; | ||
483 | |||
484 | //----------------------------------------------------------------------- | ||
485 | // Create GL drawing context | ||
486 | //----------------------------------------------------------------------- | ||
487 | |||
488 | if(mPixelFormat == NULL) | ||
489 | { | ||
490 | if(mFullscreen) | ||
491 | { | ||
492 | GLint fullscreenAttrib[] = | ||
493 | { | ||
494 | AGL_RGBA, | ||
495 | AGL_FULLSCREEN, | ||
496 | // AGL_NO_RECOVERY, // MBW -- XXX -- Not sure if we want this attribute | ||
497 | AGL_DOUBLEBUFFER, | ||
498 | AGL_CLOSEST_POLICY, | ||
499 | AGL_ACCELERATED, | ||
500 | AGL_RED_SIZE, 8, | ||
501 | AGL_GREEN_SIZE, 8, | ||
502 | AGL_BLUE_SIZE, 8, | ||
503 | AGL_ALPHA_SIZE, 8, | ||
504 | AGL_DEPTH_SIZE, 24, | ||
505 | AGL_STENCIL_SIZE, 8, | ||
506 | AGL_NONE | ||
507 | }; | ||
508 | |||
509 | llinfos << "createContext: creating fullscreen pixelformat" << llendl; | ||
510 | |||
511 | GDHandle gdhDisplay = NULL; | ||
512 | err = DMGetGDeviceByDisplayID ((DisplayIDType)mDisplay, &gdhDisplay, false); | ||
513 | |||
514 | mPixelFormat = aglChoosePixelFormat(&gdhDisplay, 1, fullscreenAttrib); | ||
515 | rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1); | ||
516 | } | ||
517 | else | ||
518 | { | ||
519 | GLint windowedAttrib[] = | ||
520 | { | ||
521 | AGL_RGBA, | ||
522 | AGL_DOUBLEBUFFER, | ||
523 | AGL_CLOSEST_POLICY, | ||
524 | AGL_ACCELERATED, | ||
525 | AGL_RED_SIZE, 8, | ||
526 | AGL_GREEN_SIZE, 8, | ||
527 | AGL_BLUE_SIZE, 8, | ||
528 | AGL_ALPHA_SIZE, 8, | ||
529 | AGL_DEPTH_SIZE, 24, | ||
530 | AGL_STENCIL_SIZE, 8, | ||
531 | AGL_NONE | ||
532 | }; | ||
533 | |||
534 | llinfos << "createContext: creating windowed pixelformat" << llendl; | ||
535 | |||
536 | mPixelFormat = aglChoosePixelFormat(NULL, 0, windowedAttrib); | ||
537 | |||
538 | GDHandle gdhDisplay = GetMainDevice(); | ||
539 | rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1); | ||
540 | } | ||
541 | |||
542 | // May want to get the real error text like this: | ||
543 | // (char *) aglErrorString(aglGetError()); | ||
544 | |||
545 | if(aglGetError() != AGL_NO_ERROR) | ||
546 | { | ||
547 | setupFailure("Can't find suitable pixel format", "Error", OSMB_OK); | ||
548 | return FALSE; | ||
549 | } | ||
550 | } | ||
551 | |||
552 | if(mPixelFormat) | ||
553 | { | ||
554 | llinfos << "createContext: creating GL context" << llendl; | ||
555 | mContext = aglCreateContext(mPixelFormat, NULL); | ||
556 | } | ||
557 | |||
558 | if(mContext == NULL) | ||
559 | { | ||
560 | setupFailure("Can't make GL context", "Error", OSMB_OK); | ||
561 | return FALSE; | ||
562 | } | ||
563 | |||
564 | gGLManager.mVRAM = 0; | ||
565 | |||
566 | if(rendererInfo != NULL) | ||
567 | { | ||
568 | GLint result; | ||
569 | |||
570 | if(aglDescribeRenderer(rendererInfo, AGL_VIDEO_MEMORY, &result)) | ||
571 | { | ||
572 | // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) returned " << result << llendl; | ||
573 | gGLManager.mVRAM = result / (1024 * 1024); | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) failed." << llendl; | ||
578 | } | ||
579 | |||
580 | // This could be useful at some point, if it takes into account the memory already used by screen buffers, etc... | ||
581 | if(aglDescribeRenderer(rendererInfo, AGL_TEXTURE_MEMORY, &result)) | ||
582 | { | ||
583 | // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) returned " << result << llendl; | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) failed." << llendl; | ||
588 | } | ||
589 | |||
590 | aglDestroyRendererInfo(rendererInfo); | ||
591 | } | ||
592 | |||
593 | // Since we just created the context, it needs to be set up. | ||
594 | glNeedsInit = TRUE; | ||
595 | } | ||
596 | |||
597 | // Hook up the context to a drawable | ||
598 | if (mFullscreen && (mOldDisplayMode != NULL)) | ||
599 | { | ||
600 | // We successfully captured the display. Use a fullscreen drawable | ||
601 | |||
602 | llinfos << "createContext: attaching fullscreen drawable" << llendl; | ||
603 | |||
604 | #if CAPTURE_ALL_DISPLAYS | ||
605 | // Capture all displays (may want to do this for final build) | ||
606 | aglDisable (mContext, AGL_FS_CAPTURE_SINGLE); | ||
607 | #else | ||
608 | // Capture only the main display (useful for debugging) | ||
609 | aglEnable (mContext, AGL_FS_CAPTURE_SINGLE); | ||
610 | #endif | ||
611 | |||
612 | if (!aglSetFullScreen (mContext, 0, 0, 0, 0)) | ||
613 | { | ||
614 | setupFailure("Can't set GL fullscreen", "Error", OSMB_OK); | ||
615 | return FALSE; | ||
616 | } | ||
617 | } | ||
618 | else if(!mFullscreen && (mWindow != NULL)) | ||
619 | { | ||
620 | llinfos << "createContext: attaching windowed drawable" << llendl; | ||
621 | |||
622 | // We created a window. Use it as the drawable. | ||
623 | if(!aglSetDrawable(mContext, GetWindowPort (mWindow))) | ||
624 | { | ||
625 | setupFailure("Can't set GL drawable", "Error", OSMB_OK); | ||
626 | return FALSE; | ||
627 | } | ||
628 | } | ||
629 | else | ||
630 | { | ||
631 | setupFailure("Can't get fullscreen or windowed drawable.", "Error", OSMB_OK); | ||
632 | return FALSE; | ||
633 | } | ||
634 | |||
635 | if(mContext != NULL) | ||
636 | { | ||
637 | llinfos << "createContext: setting current context" << llendl; | ||
638 | |||
639 | if (!aglSetCurrentContext(mContext)) | ||
640 | { | ||
641 | setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); | ||
642 | return FALSE; | ||
643 | } | ||
644 | } | ||
645 | |||
646 | if(glNeedsInit) | ||
647 | { | ||
648 | // Check for some explicitly unsupported cards. | ||
649 | const char* RENDERER = (const char*) glGetString(GL_RENDERER); | ||
650 | |||
651 | const char* CARD_LIST[] = | ||
652 | { "RAGE 128", | ||
653 | "RIVA TNT2", | ||
654 | "Intel 810", | ||
655 | "3Dfx/Voodoo3", | ||
656 | "Radeon 7000", | ||
657 | "Radeon 7200", | ||
658 | "Radeon 7500", | ||
659 | "Radeon DDR", | ||
660 | "Radeon VE", | ||
661 | "GDI Generic" }; | ||
662 | const S32 CARD_COUNT = sizeof(CARD_LIST)/sizeof(char*); | ||
663 | |||
664 | // Future candidates: | ||
665 | // ProSavage/Twister | ||
666 | // SuperSavage | ||
667 | |||
668 | S32 i; | ||
669 | for (i = 0; i < CARD_COUNT; i++) | ||
670 | { | ||
671 | if (check_for_card(RENDERER, CARD_LIST[i])) | ||
672 | { | ||
673 | close(); | ||
674 | shell_open( "help/unsupported_card.html" ); | ||
675 | return FALSE; | ||
676 | } | ||
677 | } | ||
678 | } | ||
679 | |||
680 | GLint colorBits, alphaBits, depthBits, stencilBits; | ||
681 | |||
682 | if( !aglDescribePixelFormat(mPixelFormat, AGL_BUFFER_SIZE, &colorBits) || | ||
683 | !aglDescribePixelFormat(mPixelFormat, AGL_ALPHA_SIZE, &alphaBits) || | ||
684 | !aglDescribePixelFormat(mPixelFormat, AGL_DEPTH_SIZE, &depthBits) || | ||
685 | !aglDescribePixelFormat(mPixelFormat, AGL_STENCIL_SIZE, &stencilBits)) | ||
686 | { | ||
687 | close(); | ||
688 | setupFailure("Can't get pixel format description", "Error", OSMB_OK); | ||
689 | return FALSE; | ||
690 | } | ||
691 | |||
692 | llinfos << "GL buffer: Color Bits " << S32(colorBits) | ||
693 | << " Alpha Bits " << S32(alphaBits) | ||
694 | << " Depth Bits " << S32(depthBits) | ||
695 | << " Stencil Bits" << S32(stencilBits) | ||
696 | << llendl; | ||
697 | |||
698 | if (colorBits < 32) | ||
699 | { | ||
700 | close(); | ||
701 | setupFailure( | ||
702 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
703 | "Please go to Control Panels -> Display -> Settings and\n" | ||
704 | "set the screen to 32-bit color.\n" | ||
705 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
706 | "will automatically adjust the screen each time it runs.", | ||
707 | "Error", | ||
708 | OSMB_OK); | ||
709 | return FALSE; | ||
710 | } | ||
711 | |||
712 | if (alphaBits < 8) | ||
713 | { | ||
714 | close(); | ||
715 | setupFailure( | ||
716 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
717 | "channel. Usually this is due to video card driver issues.\n" | ||
718 | "Please make sure you have the latest video card drivers installed.\n" | ||
719 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
720 | "Control Panels -> Display -> Settings.\n" | ||
721 | "If you continue to receive this message, contact customer service.", | ||
722 | "Error", | ||
723 | OSMB_OK); | ||
724 | return FALSE; | ||
725 | } | ||
726 | |||
727 | // Disable vertical sync for swap | ||
728 | GLint frames_per_swap = 0; | ||
729 | if (disable_vsync) | ||
730 | { | ||
731 | llinfos << "Disabling vertical sync" << llendl; | ||
732 | frames_per_swap = 0; | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | llinfos << "Keeping vertical sync" << llendl; | ||
737 | frames_per_swap = 1; | ||
738 | } | ||
739 | aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap); | ||
740 | |||
741 | // Don't need to get the current gamma, since there's a call that restores it to the system defaults. | ||
742 | return TRUE; | ||
743 | } | ||
744 | |||
745 | |||
746 | // changing fullscreen resolution, or switching between windowed and fullscreen mode. | ||
747 | BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) | ||
748 | { | ||
749 | BOOL needsRebuild = FALSE; | ||
750 | BOOL result = true; | ||
751 | |||
752 | if(fullscreen) | ||
753 | { | ||
754 | if(mFullscreen) | ||
755 | { | ||
756 | // Switching resolutions in fullscreen mode. Don't need to rebuild for this. | ||
757 | // Fullscreen support | ||
758 | CFDictionaryRef refDisplayMode = 0; | ||
759 | boolean_t exactMatch = false; | ||
760 | |||
761 | // Switch the display to the desired resolution and refresh | ||
762 | refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate( | ||
763 | mDisplay, | ||
764 | BITS_PER_PIXEL, | ||
765 | size.mX, | ||
766 | size.mY, | ||
767 | getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate), | ||
768 | &exactMatch); | ||
769 | |||
770 | if (refDisplayMode) | ||
771 | { | ||
772 | CGDisplaySwitchToMode (mDisplay, refDisplayMode); | ||
773 | // CFRelease(refDisplayMode); | ||
774 | } | ||
775 | |||
776 | mFullscreenWidth = CGDisplayPixelsWide(mDisplay); | ||
777 | mFullscreenHeight = CGDisplayPixelsHigh(mDisplay); | ||
778 | mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); | ||
779 | mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); | ||
780 | |||
781 | llinfos << "Switched resolution to " << mFullscreenWidth | ||
782 | << "x" << mFullscreenHeight | ||
783 | << "x" << mFullscreenBits | ||
784 | << " @ " << mFullscreenRefresh | ||
785 | << llendl; | ||
786 | |||
787 | // Update the GL context to the new screen size | ||
788 | if (!aglUpdateContext(mContext)) | ||
789 | { | ||
790 | setupFailure("Can't set GL fullscreen", "Error", OSMB_OK); | ||
791 | result = FALSE; | ||
792 | } | ||
793 | } | ||
794 | else | ||
795 | { | ||
796 | // Switching from windowed to fullscreen | ||
797 | needsRebuild = TRUE; | ||
798 | } | ||
799 | } | ||
800 | else | ||
801 | { | ||
802 | if(mFullscreen) | ||
803 | { | ||
804 | // Switching from fullscreen to windowed | ||
805 | needsRebuild = TRUE; | ||
806 | } | ||
807 | else | ||
808 | { | ||
809 | // Windowed to windowed -- not sure why we would be called like this. Just change the window size. | ||
810 | // The bounds changed event handler will do the rest. | ||
811 | if(mWindow != NULL) | ||
812 | { | ||
813 | ::SizeWindow(mWindow, size.mX, size.mY, true); | ||
814 | } | ||
815 | } | ||
816 | } | ||
817 | |||
818 | stop_glerror(); | ||
819 | if(needsRebuild) | ||
820 | { | ||
821 | destroyContext(); | ||
822 | result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); | ||
823 | if (result) | ||
824 | { | ||
825 | if(mWindow != NULL) | ||
826 | { | ||
827 | MacShowWindow(mWindow); | ||
828 | BringToFront(mWindow); | ||
829 | } | ||
830 | |||
831 | llverify(gGLManager.initGL()); | ||
832 | |||
833 | //start with arrow cursor | ||
834 | initCursors(); | ||
835 | setCursor( UI_CURSOR_ARROW ); | ||
836 | } | ||
837 | } | ||
838 | |||
839 | stop_glerror(); | ||
840 | |||
841 | return result; | ||
842 | } | ||
843 | |||
844 | void LLWindowMacOSX::destroyContext() | ||
845 | { | ||
846 | if (!mContext) | ||
847 | { | ||
848 | // We don't have a context | ||
849 | return; | ||
850 | } | ||
851 | // Unhook the GL context from any drawable it may have | ||
852 | if(mContext != NULL) | ||
853 | { | ||
854 | llinfos << "destroyContext: unhooking drawable " << llendl; | ||
855 | |||
856 | aglSetCurrentContext (NULL); | ||
857 | aglSetDrawable(mContext, NULL); | ||
858 | } | ||
859 | |||
860 | // Make sure the display resolution gets restored | ||
861 | if(mOldDisplayMode != NULL) | ||
862 | { | ||
863 | llinfos << "destroyContext: restoring display resolution " << llendl; | ||
864 | |||
865 | CGDisplaySwitchToMode (mDisplay, mOldDisplayMode); | ||
866 | |||
867 | #if CAPTURE_ALL_DISPLAYS | ||
868 | // Uncapture all displays (may want to do this for final build) | ||
869 | CGReleaseAllDisplays (); | ||
870 | #else | ||
871 | // Uncapture only the main display (useful for debugging) | ||
872 | CGDisplayRelease (mDisplay); | ||
873 | #endif | ||
874 | |||
875 | // CFRelease(mOldDisplayMode); | ||
876 | |||
877 | mOldDisplayMode = NULL; | ||
878 | |||
879 | // Remove the global event handlers the fullscreen case needed | ||
880 | RemoveEventTypesFromHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList); | ||
881 | } | ||
882 | |||
883 | // Clean up remaining GL state before blowing away window | ||
884 | gGLManager.shutdownGL(); | ||
885 | |||
886 | // Clean up the pixel format | ||
887 | if(mPixelFormat != NULL) | ||
888 | { | ||
889 | llinfos << "destroyContext: destroying pixel format " << llendl; | ||
890 | aglDestroyPixelFormat(mPixelFormat); | ||
891 | mPixelFormat = NULL; | ||
892 | } | ||
893 | |||
894 | // Remove any Carbon Event handlers we installed | ||
895 | if(mGlobalHandlerRef != NULL) | ||
896 | { | ||
897 | llinfos << "destroyContext: removing global event handler" << llendl; | ||
898 | RemoveEventHandler(mGlobalHandlerRef); | ||
899 | mGlobalHandlerRef = NULL; | ||
900 | } | ||
901 | |||
902 | if(mWindowHandlerRef != NULL) | ||
903 | { | ||
904 | llinfos << "destroyContext: removing window event handler" << llendl; | ||
905 | RemoveEventHandler(mWindowHandlerRef); | ||
906 | mWindowHandlerRef = NULL; | ||
907 | } | ||
908 | |||
909 | // Close the window | ||
910 | if(mWindow != NULL) | ||
911 | { | ||
912 | llinfos << "destroyContext: disposing window" << llendl; | ||
913 | DisposeWindow(mWindow); | ||
914 | mWindow = NULL; | ||
915 | } | ||
916 | |||
917 | // Clean up the GL context | ||
918 | if(mContext != NULL) | ||
919 | { | ||
920 | llinfos << "destroyContext: destroying GL context" << llendl; | ||
921 | aglDestroyContext(mContext); | ||
922 | mContext = NULL; | ||
923 | } | ||
924 | |||
925 | } | ||
926 | |||
927 | LLWindowMacOSX::~LLWindowMacOSX() | ||
928 | { | ||
929 | destroyContext(); | ||
930 | |||
931 | if(mSupportedResolutions != NULL) | ||
932 | { | ||
933 | delete []mSupportedResolutions; | ||
934 | } | ||
935 | |||
936 | gWindowImplementation = NULL; | ||
937 | |||
938 | } | ||
939 | |||
940 | |||
941 | void LLWindowMacOSX::show() | ||
942 | { | ||
943 | if(IsWindowCollapsed(mWindow)) | ||
944 | CollapseWindow(mWindow, false); | ||
945 | |||
946 | MacShowWindow(mWindow); | ||
947 | BringToFront(mWindow); | ||
948 | } | ||
949 | |||
950 | void LLWindowMacOSX::hide() | ||
951 | { | ||
952 | setMouseClipping(FALSE); | ||
953 | HideWindow(mWindow); | ||
954 | } | ||
955 | |||
956 | void LLWindowMacOSX::minimize() | ||
957 | { | ||
958 | setMouseClipping(FALSE); | ||
959 | showCursor(); | ||
960 | CollapseWindow(mWindow, true); | ||
961 | } | ||
962 | |||
963 | void LLWindowMacOSX::restore() | ||
964 | { | ||
965 | show(); | ||
966 | } | ||
967 | |||
968 | |||
969 | // close() destroys all OS-specific code associated with a window. | ||
970 | // Usually called from LLWindowManager::destroyWindow() | ||
971 | void LLWindowMacOSX::close() | ||
972 | { | ||
973 | // Is window is already closed? | ||
974 | // if (!mWindow) | ||
975 | // { | ||
976 | // return; | ||
977 | // } | ||
978 | |||
979 | // Make sure cursor is visible and we haven't mangled the clipping state. | ||
980 | setMouseClipping(FALSE); | ||
981 | showCursor(); | ||
982 | |||
983 | destroyContext(); | ||
984 | } | ||
985 | |||
986 | BOOL LLWindowMacOSX::isValid() | ||
987 | { | ||
988 | if(mFullscreen) | ||
989 | { | ||
990 | return(TRUE); | ||
991 | } | ||
992 | |||
993 | return (mWindow != NULL); | ||
994 | } | ||
995 | |||
996 | BOOL LLWindowMacOSX::getVisible() | ||
997 | { | ||
998 | BOOL result = FALSE; | ||
999 | |||
1000 | if(mFullscreen) | ||
1001 | { | ||
1002 | result = TRUE; | ||
1003 | }if (mWindow) | ||
1004 | { | ||
1005 | if(MacIsWindowVisible(mWindow)) | ||
1006 | result = TRUE; | ||
1007 | } | ||
1008 | |||
1009 | return(result); | ||
1010 | } | ||
1011 | |||
1012 | BOOL LLWindowMacOSX::getMinimized() | ||
1013 | { | ||
1014 | BOOL result = FALSE; | ||
1015 | |||
1016 | // Since the set of states where we want to act "minimized" is non-trivial, it's easier to | ||
1017 | // track things locally than to try and retrieve the state from the window manager. | ||
1018 | result = mMinimized; | ||
1019 | |||
1020 | return(result); | ||
1021 | } | ||
1022 | |||
1023 | BOOL LLWindowMacOSX::getMaximized() | ||
1024 | { | ||
1025 | BOOL result = FALSE; | ||
1026 | |||
1027 | if (mWindow) | ||
1028 | { | ||
1029 | // TODO | ||
1030 | } | ||
1031 | |||
1032 | return(result); | ||
1033 | } | ||
1034 | |||
1035 | BOOL LLWindowMacOSX::maximize() | ||
1036 | { | ||
1037 | // TODO | ||
1038 | return FALSE; | ||
1039 | } | ||
1040 | |||
1041 | BOOL LLWindowMacOSX::getFullscreen() | ||
1042 | { | ||
1043 | return mFullscreen; | ||
1044 | } | ||
1045 | |||
1046 | void LLWindowMacOSX::gatherInput() | ||
1047 | { | ||
1048 | // stop bouncing icon after fixed period of time | ||
1049 | if (mBounceTimer.getStarted() && mBounceTimer.getElapsedTimeF32() > mBounceTime) | ||
1050 | { | ||
1051 | stopDockTileBounce(); | ||
1052 | } | ||
1053 | |||
1054 | // Use the old-school version so we get AppleEvent handler dispatch and menuselect handling. | ||
1055 | // Anything that has an event handler will get processed inside WaitNextEvent, so we only need to handle | ||
1056 | // the odd stuff here. | ||
1057 | EventRecord evt; | ||
1058 | while(WaitNextEvent(everyEvent, &evt, 0, NULL)) | ||
1059 | { | ||
1060 | // printf("WaitNextEvent returned true, event is %d.\n", evt.what); | ||
1061 | switch(evt.what) | ||
1062 | { | ||
1063 | case mouseDown: | ||
1064 | { | ||
1065 | short part; | ||
1066 | WindowRef window; | ||
1067 | long selectResult; | ||
1068 | part = FindWindow(evt.where, &window); | ||
1069 | switch ( part ) | ||
1070 | { | ||
1071 | case inMenuBar: | ||
1072 | selectResult = MenuSelect(evt.where); | ||
1073 | |||
1074 | HiliteMenu(0); | ||
1075 | break; | ||
1076 | } | ||
1077 | } | ||
1078 | break; | ||
1079 | |||
1080 | case kHighLevelEvent: | ||
1081 | AEProcessAppleEvent (&evt); | ||
1082 | break; | ||
1083 | |||
1084 | case updateEvt: | ||
1085 | // We shouldn't be getting these regularly (since our window will be buffered), but we need to handle them correctly... | ||
1086 | BeginUpdate((WindowRef)evt.message); | ||
1087 | EndUpdate((WindowRef)evt.message); | ||
1088 | break; | ||
1089 | |||
1090 | } | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) | ||
1095 | { | ||
1096 | Rect window_rect; | ||
1097 | OSStatus err = -1; | ||
1098 | |||
1099 | if(mFullscreen) | ||
1100 | { | ||
1101 | position->mX = 0; | ||
1102 | position->mY = 0; | ||
1103 | err = noErr; | ||
1104 | } | ||
1105 | else if(mWindow) | ||
1106 | { | ||
1107 | err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); | ||
1108 | |||
1109 | position->mX = window_rect.left; | ||
1110 | position->mY = window_rect.top; | ||
1111 | } | ||
1112 | else | ||
1113 | { | ||
1114 | llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; | ||
1115 | } | ||
1116 | |||
1117 | return (err == noErr); | ||
1118 | } | ||
1119 | |||
1120 | BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) | ||
1121 | { | ||
1122 | Rect window_rect; | ||
1123 | OSStatus err = -1; | ||
1124 | |||
1125 | if(mFullscreen) | ||
1126 | { | ||
1127 | size->mX = mFullscreenWidth; | ||
1128 | size->mY = mFullscreenHeight; | ||
1129 | err = noErr; | ||
1130 | } | ||
1131 | else if(mWindow) | ||
1132 | { | ||
1133 | err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); | ||
1134 | |||
1135 | size->mX = window_rect.right - window_rect.left; | ||
1136 | size->mY = window_rect.bottom - window_rect.top; | ||
1137 | } | ||
1138 | else | ||
1139 | { | ||
1140 | llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; | ||
1141 | } | ||
1142 | |||
1143 | return (err == noErr); | ||
1144 | } | ||
1145 | |||
1146 | BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) | ||
1147 | { | ||
1148 | Rect window_rect; | ||
1149 | OSStatus err = -1; | ||
1150 | |||
1151 | if(mFullscreen) | ||
1152 | { | ||
1153 | size->mX = mFullscreenWidth; | ||
1154 | size->mY = mFullscreenHeight; | ||
1155 | err = noErr; | ||
1156 | } | ||
1157 | else if(mWindow) | ||
1158 | { | ||
1159 | err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect); | ||
1160 | |||
1161 | size->mX = window_rect.right - window_rect.left; | ||
1162 | size->mY = window_rect.bottom - window_rect.top; | ||
1163 | } | ||
1164 | else | ||
1165 | { | ||
1166 | llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl; | ||
1167 | } | ||
1168 | |||
1169 | return (err == noErr); | ||
1170 | } | ||
1171 | |||
1172 | BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) | ||
1173 | { | ||
1174 | if(mWindow) | ||
1175 | { | ||
1176 | MacMoveWindow(mWindow, position.mX, position.mY, false); | ||
1177 | } | ||
1178 | |||
1179 | return TRUE; | ||
1180 | } | ||
1181 | |||
1182 | BOOL LLWindowMacOSX::setSize(const LLCoordScreen size) | ||
1183 | { | ||
1184 | if(mWindow) | ||
1185 | { | ||
1186 | SizeWindow(mWindow, size.mX, size.mY, true); | ||
1187 | } | ||
1188 | |||
1189 | return TRUE; | ||
1190 | } | ||
1191 | |||
1192 | void LLWindowMacOSX::swapBuffers() | ||
1193 | { | ||
1194 | aglSwapBuffers(mContext); | ||
1195 | } | ||
1196 | |||
1197 | F32 LLWindowMacOSX::getGamma() | ||
1198 | { | ||
1199 | F32 result = 1.8; // Default to something sane | ||
1200 | |||
1201 | CGGammaValue redMin; | ||
1202 | CGGammaValue redMax; | ||
1203 | CGGammaValue redGamma; | ||
1204 | CGGammaValue greenMin; | ||
1205 | CGGammaValue greenMax; | ||
1206 | CGGammaValue greenGamma; | ||
1207 | CGGammaValue blueMin; | ||
1208 | CGGammaValue blueMax; | ||
1209 | CGGammaValue blueGamma; | ||
1210 | |||
1211 | if(CGGetDisplayTransferByFormula( | ||
1212 | mDisplay, | ||
1213 | &redMin, | ||
1214 | &redMax, | ||
1215 | &redGamma, | ||
1216 | &greenMin, | ||
1217 | &greenMax, | ||
1218 | &greenGamma, | ||
1219 | &blueMin, | ||
1220 | &blueMax, | ||
1221 | &blueGamma) == noErr) | ||
1222 | { | ||
1223 | // So many choices... | ||
1224 | // Let's just return the green channel gamma for now. | ||
1225 | result = greenGamma; | ||
1226 | } | ||
1227 | |||
1228 | return result; | ||
1229 | } | ||
1230 | |||
1231 | BOOL LLWindowMacOSX::restoreGamma() | ||
1232 | { | ||
1233 | CGDisplayRestoreColorSyncSettings(); | ||
1234 | return true; | ||
1235 | } | ||
1236 | |||
1237 | BOOL LLWindowMacOSX::setGamma(const F32 gamma) | ||
1238 | { | ||
1239 | CGGammaValue redMin; | ||
1240 | CGGammaValue redMax; | ||
1241 | CGGammaValue redGamma; | ||
1242 | CGGammaValue greenMin; | ||
1243 | CGGammaValue greenMax; | ||
1244 | CGGammaValue greenGamma; | ||
1245 | CGGammaValue blueMin; | ||
1246 | CGGammaValue blueMax; | ||
1247 | CGGammaValue blueGamma; | ||
1248 | |||
1249 | // MBW -- XXX -- Should we allow this in windowed mode? | ||
1250 | |||
1251 | if(CGGetDisplayTransferByFormula( | ||
1252 | mDisplay, | ||
1253 | &redMin, | ||
1254 | &redMax, | ||
1255 | &redGamma, | ||
1256 | &greenMin, | ||
1257 | &greenMax, | ||
1258 | &greenGamma, | ||
1259 | &blueMin, | ||
1260 | &blueMax, | ||
1261 | &blueGamma) != noErr) | ||
1262 | { | ||
1263 | return false; | ||
1264 | } | ||
1265 | |||
1266 | if(CGSetDisplayTransferByFormula( | ||
1267 | mDisplay, | ||
1268 | redMin, | ||
1269 | redMax, | ||
1270 | gamma, | ||
1271 | greenMin, | ||
1272 | greenMax, | ||
1273 | gamma, | ||
1274 | blueMin, | ||
1275 | blueMax, | ||
1276 | gamma) != noErr) | ||
1277 | { | ||
1278 | return false; | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | return true; | ||
1283 | } | ||
1284 | |||
1285 | BOOL LLWindowMacOSX::isCursorHidden() | ||
1286 | { | ||
1287 | return mCursorHidden; | ||
1288 | } | ||
1289 | |||
1290 | |||
1291 | |||
1292 | // Constrains the mouse to the window. | ||
1293 | void LLWindowMacOSX::setMouseClipping( BOOL b ) | ||
1294 | { | ||
1295 | // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. | ||
1296 | mIsMouseClipping = b; | ||
1297 | |||
1298 | if(b) | ||
1299 | { | ||
1300 | // llinfos << "setMouseClipping(TRUE)" << llendl | ||
1301 | } | ||
1302 | else | ||
1303 | { | ||
1304 | // llinfos << "setMouseClipping(FALSE)" << llendl | ||
1305 | } | ||
1306 | |||
1307 | adjustCursorDecouple(); | ||
1308 | } | ||
1309 | |||
1310 | BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) | ||
1311 | { | ||
1312 | BOOL result = FALSE; | ||
1313 | LLCoordScreen screen_pos; | ||
1314 | |||
1315 | if (!convertCoords(position, &screen_pos)) | ||
1316 | { | ||
1317 | return FALSE; | ||
1318 | } | ||
1319 | |||
1320 | CGPoint newPosition; | ||
1321 | |||
1322 | // llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl | ||
1323 | |||
1324 | newPosition.x = screen_pos.mX; | ||
1325 | newPosition.y = screen_pos.mY; | ||
1326 | |||
1327 | CGSetLocalEventsSuppressionInterval(0.0); | ||
1328 | if(CGWarpMouseCursorPosition(newPosition) == noErr) | ||
1329 | { | ||
1330 | result = TRUE; | ||
1331 | } | ||
1332 | |||
1333 | // Under certain circumstances, this will trigger us to decouple the cursor. | ||
1334 | adjustCursorDecouple(true); | ||
1335 | |||
1336 | return result; | ||
1337 | } | ||
1338 | |||
1339 | static void fixOrigin(void) | ||
1340 | { | ||
1341 | GrafPtr port; | ||
1342 | Rect portrect; | ||
1343 | |||
1344 | ::GetPort(&port); | ||
1345 | ::GetPortBounds(port, &portrect); | ||
1346 | if((portrect.left != 0) || (portrect.top != 0)) | ||
1347 | { | ||
1348 | // Mozilla sometimes changes our port origin. Fuckers. | ||
1349 | ::SetOrigin(0,0); | ||
1350 | } | ||
1351 | } | ||
1352 | |||
1353 | BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) | ||
1354 | { | ||
1355 | Point cursor_point; | ||
1356 | LLCoordScreen screen_pos; | ||
1357 | GrafPtr save; | ||
1358 | |||
1359 | if(mWindow == NULL) | ||
1360 | return FALSE; | ||
1361 | |||
1362 | ::GetPort(&save); | ||
1363 | ::SetPort(GetWindowPort(mWindow)); | ||
1364 | fixOrigin(); | ||
1365 | |||
1366 | // gets the mouse location in local coordinates | ||
1367 | ::GetMouse(&cursor_point); | ||
1368 | |||
1369 | // lldebugs << "getCursorPosition(): cursor is at " << cursor_point.h << ", " << cursor_point.v << " port origin: " << portrect.left << ", " << portrect.top << llendl; | ||
1370 | |||
1371 | ::SetPort(save); | ||
1372 | |||
1373 | if(mCursorDecoupled) | ||
1374 | { | ||
1375 | // CGMouseDelta x, y; | ||
1376 | |||
1377 | // If the cursor's decoupled, we need to read the latest movement delta as well. | ||
1378 | // CGGetLastMouseDelta( &x, &y ); | ||
1379 | // cursor_point.h += x; | ||
1380 | // cursor_point.v += y; | ||
1381 | |||
1382 | // CGGetLastMouseDelta may behave strangely when the cursor's first captured. | ||
1383 | // Stash in the event handler instead. | ||
1384 | cursor_point.h += mCursorLastEventDeltaX; | ||
1385 | cursor_point.v += mCursorLastEventDeltaY; | ||
1386 | } | ||
1387 | |||
1388 | position->mX = cursor_point.h; | ||
1389 | position->mY = cursor_point.v; | ||
1390 | |||
1391 | return TRUE; | ||
1392 | } | ||
1393 | |||
1394 | void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) | ||
1395 | { | ||
1396 | if(mIsMouseClipping && mCursorHidden) | ||
1397 | { | ||
1398 | if(warpingMouse) | ||
1399 | { | ||
1400 | // The cursor should be decoupled. Make sure it is. | ||
1401 | if(!mCursorDecoupled) | ||
1402 | { | ||
1403 | // llinfos << "adjustCursorDecouple: decoupling cursor" << llendl; | ||
1404 | CGAssociateMouseAndMouseCursorPosition(false); | ||
1405 | mCursorDecoupled = true; | ||
1406 | mCursorIgnoreNextDelta = TRUE; | ||
1407 | } | ||
1408 | } | ||
1409 | } | ||
1410 | else | ||
1411 | { | ||
1412 | // The cursor should not be decoupled. Make sure it isn't. | ||
1413 | if(mCursorDecoupled) | ||
1414 | { | ||
1415 | // llinfos << "adjustCursorDecouple: recoupling cursor" << llendl; | ||
1416 | CGAssociateMouseAndMouseCursorPosition(true); | ||
1417 | mCursorDecoupled = false; | ||
1418 | } | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | F32 LLWindowMacOSX::getNativeAspectRatio() | ||
1423 | { | ||
1424 | if (mFullscreen) | ||
1425 | { | ||
1426 | return (F32)mFullscreenWidth / (F32)mFullscreenHeight; | ||
1427 | } | ||
1428 | else | ||
1429 | { | ||
1430 | // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution | ||
1431 | // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. | ||
1432 | |||
1433 | if (mOverrideAspectRatio > 0.f) | ||
1434 | { | ||
1435 | return mOverrideAspectRatio; | ||
1436 | } | ||
1437 | |||
1438 | return mOriginalAspectRatio; | ||
1439 | } | ||
1440 | } | ||
1441 | |||
1442 | F32 LLWindowMacOSX::getPixelAspectRatio() | ||
1443 | { | ||
1444 | //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode | ||
1445 | return 1.f; | ||
1446 | } | ||
1447 | |||
1448 | //static SInt32 oldWindowLevel; | ||
1449 | |||
1450 | // MBW -- XXX -- There's got to be a better way than this. Find it, please... | ||
1451 | |||
1452 | void LLWindowMacOSX::beforeDialog() | ||
1453 | { | ||
1454 | if(mFullscreen) | ||
1455 | { | ||
1456 | |||
1457 | #if CAPTURE_ALL_DISPLAYS | ||
1458 | // Uncapture all displays (may want to do this for final build) | ||
1459 | CGReleaseAllDisplays (); | ||
1460 | #else | ||
1461 | // Uncapture only the main display (useful for debugging) | ||
1462 | CGDisplayRelease (mDisplay); | ||
1463 | #endif | ||
1464 | // kDocumentWindowClass | ||
1465 | // kMovableModalWindowClass | ||
1466 | // kAllWindowClasses | ||
1467 | |||
1468 | // GLint order = 0; | ||
1469 | // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order); | ||
1470 | aglSetDrawable(mContext, NULL); | ||
1471 | // GetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), &oldWindowLevel); | ||
1472 | // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), CGShieldingWindowLevel()); | ||
1473 | |||
1474 | mHandsOffEvents = TRUE; | ||
1475 | |||
1476 | } | ||
1477 | } | ||
1478 | |||
1479 | void LLWindowMacOSX::afterDialog() | ||
1480 | { | ||
1481 | if(mFullscreen) | ||
1482 | { | ||
1483 | mHandsOffEvents = FALSE; | ||
1484 | |||
1485 | // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), oldWindowLevel); | ||
1486 | aglSetFullScreen(mContext, 0, 0, 0, 0); | ||
1487 | // GLint order = 1; | ||
1488 | // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order); | ||
1489 | |||
1490 | #if CAPTURE_ALL_DISPLAYS | ||
1491 | // Capture all displays (may want to do this for final build) | ||
1492 | CGCaptureAllDisplays (); | ||
1493 | #else | ||
1494 | // Capture only the main display (useful for debugging) | ||
1495 | CGDisplayCapture (mDisplay); | ||
1496 | #endif | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | |||
1501 | S32 LLWindowMacOSX::stat(const char* file_name, struct stat* stat_info) | ||
1502 | { | ||
1503 | return ::stat( file_name, stat_info ); | ||
1504 | } | ||
1505 | |||
1506 | void LLWindowMacOSX::flashIcon(F32 seconds) | ||
1507 | { | ||
1508 | // Don't do this if we're already started, since this would try to install the NMRec twice. | ||
1509 | if(!mBounceTimer.getStarted()) | ||
1510 | { | ||
1511 | OSErr err; | ||
1512 | |||
1513 | mBounceTime = seconds; | ||
1514 | memset(&mBounceRec, sizeof(mBounceRec), 0); | ||
1515 | mBounceRec.qType = nmType; | ||
1516 | mBounceRec.nmMark = 1; | ||
1517 | err = NMInstall(&mBounceRec); | ||
1518 | if(err == noErr) | ||
1519 | { | ||
1520 | mBounceTimer.start(); | ||
1521 | } | ||
1522 | else | ||
1523 | { | ||
1524 | // This is very not-fatal (only problem is the icon will not bounce), but we'd like to find out about it somehow... | ||
1525 | llinfos << "NMInstall failed with error code " << err << llendl; | ||
1526 | } | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | BOOL LLWindowMacOSX::isClipboardTextAvailable() | ||
1531 | { | ||
1532 | OSStatus err; | ||
1533 | ScrapRef scrap; | ||
1534 | ScrapFlavorFlags flags; | ||
1535 | BOOL result = false; | ||
1536 | |||
1537 | err = GetCurrentScrap(&scrap); | ||
1538 | |||
1539 | if(err == noErr) | ||
1540 | { | ||
1541 | err = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &flags); | ||
1542 | } | ||
1543 | |||
1544 | if(err == noErr) | ||
1545 | result = true; | ||
1546 | |||
1547 | return result; | ||
1548 | } | ||
1549 | |||
1550 | BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) | ||
1551 | { | ||
1552 | OSStatus err; | ||
1553 | ScrapRef scrap; | ||
1554 | Size len; | ||
1555 | BOOL result = false; | ||
1556 | |||
1557 | err = GetCurrentScrap(&scrap); | ||
1558 | |||
1559 | if(err == noErr) | ||
1560 | { | ||
1561 | err = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &len); | ||
1562 | } | ||
1563 | |||
1564 | if((err == noErr) && (len > 0)) | ||
1565 | { | ||
1566 | int u16len = len / sizeof(U16); | ||
1567 | U16 *temp = new U16[u16len + 1]; | ||
1568 | if (temp) | ||
1569 | { | ||
1570 | memset(temp, 0, (u16len + 1) * sizeof(temp[0])); | ||
1571 | err = GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &len, temp); | ||
1572 | if (err == noErr) | ||
1573 | { | ||
1574 | // convert \r\n to \n and \r to \n in the incoming text. | ||
1575 | U16 *s, *d; | ||
1576 | for(s = d = temp; s[0] != '\0'; s++, d++) | ||
1577 | { | ||
1578 | if(s[0] == '\r') | ||
1579 | { | ||
1580 | if(s[1] == '\n') | ||
1581 | { | ||
1582 | // CRLF, a.k.a. DOS newline. Collapse to a single '\n'. | ||
1583 | s++; | ||
1584 | } | ||
1585 | |||
1586 | d[0] = '\n'; | ||
1587 | } | ||
1588 | else | ||
1589 | { | ||
1590 | d[0] = s[0]; | ||
1591 | } | ||
1592 | } | ||
1593 | |||
1594 | d[0] = '\0'; | ||
1595 | |||
1596 | dst = utf16str_to_wstring(temp); | ||
1597 | |||
1598 | result = true; | ||
1599 | } | ||
1600 | delete[] temp; | ||
1601 | } | ||
1602 | } | ||
1603 | |||
1604 | return result; | ||
1605 | } | ||
1606 | |||
1607 | BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) | ||
1608 | { | ||
1609 | OSStatus err; | ||
1610 | ScrapRef scrap; | ||
1611 | //Size len; | ||
1612 | //char *temp; | ||
1613 | BOOL result = false; | ||
1614 | |||
1615 | if (!s.empty()) | ||
1616 | { | ||
1617 | err = GetCurrentScrap(&scrap); | ||
1618 | if (err == noErr) | ||
1619 | err = ClearScrap(&scrap); | ||
1620 | |||
1621 | if (err == noErr) | ||
1622 | { | ||
1623 | llutf16string utf16str = wstring_to_utf16str(s); | ||
1624 | size_t u16len = utf16str.length() * sizeof(U16); | ||
1625 | err = PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone, u16len, utf16str.data()); | ||
1626 | if (err == noErr) | ||
1627 | result = true; | ||
1628 | } | ||
1629 | } | ||
1630 | |||
1631 | return result; | ||
1632 | } | ||
1633 | |||
1634 | |||
1635 | BOOL LLWindowMacOSX::sendEmail(const char* address, const char* subject, const char* body_text, | ||
1636 | const char* attachment, const char* attachment_displayed_name ) | ||
1637 | { | ||
1638 | // MBW -- XXX -- Um... yeah. I'll get to this later. | ||
1639 | |||
1640 | return false; | ||
1641 | } | ||
1642 | |||
1643 | |||
1644 | // protected | ||
1645 | BOOL LLWindowMacOSX::resetDisplayResolution() | ||
1646 | { | ||
1647 | // This is only called from elsewhere in this class, and it's not used by the Mac implementation. | ||
1648 | return true; | ||
1649 | } | ||
1650 | |||
1651 | |||
1652 | LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) | ||
1653 | { | ||
1654 | if (!mSupportedResolutions) | ||
1655 | { | ||
1656 | CFArrayRef modes = CGDisplayAvailableModes(mDisplay); | ||
1657 | |||
1658 | if(modes != NULL) | ||
1659 | { | ||
1660 | CFIndex index, cnt; | ||
1661 | |||
1662 | mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; | ||
1663 | mNumSupportedResolutions = 0; | ||
1664 | |||
1665 | // Examine each mode | ||
1666 | cnt = CFArrayGetCount( modes ); | ||
1667 | |||
1668 | for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) | ||
1669 | { | ||
1670 | // Pull the mode dictionary out of the CFArray | ||
1671 | CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); | ||
1672 | long width = getDictLong(mode, kCGDisplayWidth); | ||
1673 | long height = getDictLong(mode, kCGDisplayHeight); | ||
1674 | long bits = getDictLong(mode, kCGDisplayBitsPerPixel); | ||
1675 | |||
1676 | if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) | ||
1677 | { | ||
1678 | BOOL resolution_exists = FALSE; | ||
1679 | for(S32 i = 0; i < mNumSupportedResolutions; i++) | ||
1680 | { | ||
1681 | if (mSupportedResolutions[i].mWidth == width && | ||
1682 | mSupportedResolutions[i].mHeight == height) | ||
1683 | { | ||
1684 | resolution_exists = TRUE; | ||
1685 | } | ||
1686 | } | ||
1687 | if (!resolution_exists) | ||
1688 | { | ||
1689 | mSupportedResolutions[mNumSupportedResolutions].mWidth = width; | ||
1690 | mSupportedResolutions[mNumSupportedResolutions].mHeight = height; | ||
1691 | mNumSupportedResolutions++; | ||
1692 | } | ||
1693 | } | ||
1694 | } | ||
1695 | } | ||
1696 | } | ||
1697 | |||
1698 | num_resolutions = mNumSupportedResolutions; | ||
1699 | return mSupportedResolutions; | ||
1700 | } | ||
1701 | |||
1702 | BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) | ||
1703 | { | ||
1704 | S32 client_height; | ||
1705 | Rect client_rect; | ||
1706 | |||
1707 | if(mFullscreen) | ||
1708 | { | ||
1709 | // In the fullscreen case, the "window" is the entire screen. | ||
1710 | client_rect.left = 0; | ||
1711 | client_rect.top = 0; | ||
1712 | client_rect.right = mFullscreenWidth; | ||
1713 | client_rect.bottom = mFullscreenHeight; | ||
1714 | } | ||
1715 | else if (!mWindow || | ||
1716 | (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) || | ||
1717 | NULL == to) | ||
1718 | { | ||
1719 | return FALSE; | ||
1720 | } | ||
1721 | |||
1722 | to->mX = from.mX; | ||
1723 | client_height = client_rect.bottom - client_rect.top; | ||
1724 | to->mY = client_height - from.mY - 1; | ||
1725 | |||
1726 | return TRUE; | ||
1727 | } | ||
1728 | |||
1729 | BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) | ||
1730 | { | ||
1731 | S32 client_height; | ||
1732 | Rect client_rect; | ||
1733 | |||
1734 | if(mFullscreen) | ||
1735 | { | ||
1736 | // In the fullscreen case, the "window" is the entire screen. | ||
1737 | client_rect.left = 0; | ||
1738 | client_rect.top = 0; | ||
1739 | client_rect.right = mFullscreenWidth; | ||
1740 | client_rect.bottom = mFullscreenHeight; | ||
1741 | } | ||
1742 | else if (!mWindow || | ||
1743 | (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) || | ||
1744 | NULL == to) | ||
1745 | { | ||
1746 | return FALSE; | ||
1747 | } | ||
1748 | |||
1749 | to->mX = from.mX; | ||
1750 | client_height = client_rect.bottom - client_rect.top; | ||
1751 | to->mY = client_height - from.mY - 1; | ||
1752 | |||
1753 | return TRUE; | ||
1754 | } | ||
1755 | |||
1756 | BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) | ||
1757 | { | ||
1758 | if(mFullscreen) | ||
1759 | { | ||
1760 | // In the fullscreen case, window and screen coordinates are the same. | ||
1761 | to->mX = from.mX; | ||
1762 | to->mY = from.mY; | ||
1763 | return TRUE; | ||
1764 | } | ||
1765 | else if(mWindow) | ||
1766 | { | ||
1767 | GrafPtr save; | ||
1768 | Point mouse_point; | ||
1769 | |||
1770 | mouse_point.h = from.mX; | ||
1771 | mouse_point.v = from.mY; | ||
1772 | |||
1773 | ::GetPort(&save); | ||
1774 | ::SetPort(GetWindowPort(mWindow)); | ||
1775 | fixOrigin(); | ||
1776 | |||
1777 | ::GlobalToLocal(&mouse_point); | ||
1778 | |||
1779 | to->mX = mouse_point.h; | ||
1780 | to->mY = mouse_point.v; | ||
1781 | |||
1782 | ::SetPort(save); | ||
1783 | |||
1784 | return TRUE; | ||
1785 | } | ||
1786 | |||
1787 | return FALSE; | ||
1788 | } | ||
1789 | |||
1790 | BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) | ||
1791 | { | ||
1792 | if(mFullscreen) | ||
1793 | { | ||
1794 | // In the fullscreen case, window and screen coordinates are the same. | ||
1795 | to->mX = from.mX; | ||
1796 | to->mY = from.mY; | ||
1797 | return TRUE; | ||
1798 | } | ||
1799 | else if(mWindow) | ||
1800 | { | ||
1801 | GrafPtr save; | ||
1802 | Point mouse_point; | ||
1803 | |||
1804 | mouse_point.h = from.mX; | ||
1805 | mouse_point.v = from.mY; | ||
1806 | ::GetPort(&save); | ||
1807 | ::SetPort(GetWindowPort(mWindow)); | ||
1808 | fixOrigin(); | ||
1809 | |||
1810 | LocalToGlobal(&mouse_point); | ||
1811 | |||
1812 | to->mX = mouse_point.h; | ||
1813 | to->mY = mouse_point.v; | ||
1814 | |||
1815 | ::SetPort(save); | ||
1816 | |||
1817 | return TRUE; | ||
1818 | } | ||
1819 | |||
1820 | return FALSE; | ||
1821 | } | ||
1822 | |||
1823 | BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) | ||
1824 | { | ||
1825 | LLCoordWindow window_coord; | ||
1826 | |||
1827 | return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); | ||
1828 | } | ||
1829 | |||
1830 | BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) | ||
1831 | { | ||
1832 | LLCoordWindow window_coord; | ||
1833 | |||
1834 | return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); | ||
1835 | } | ||
1836 | |||
1837 | |||
1838 | |||
1839 | |||
1840 | void LLWindowMacOSX::setupFailure(const char* text, const char* caption, U32 type) | ||
1841 | { | ||
1842 | destroyContext(); | ||
1843 | |||
1844 | OSMessageBox(text, caption, type); | ||
1845 | } | ||
1846 | |||
1847 | pascal OSStatus LLWindowMacOSX::staticEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData) | ||
1848 | { | ||
1849 | LLWindowMacOSX *self = (LLWindowMacOSX*)userData; | ||
1850 | |||
1851 | return(self->eventHandler(myHandler, event)); | ||
1852 | } | ||
1853 | |||
1854 | OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef event) | ||
1855 | { | ||
1856 | OSStatus result = eventNotHandledErr; | ||
1857 | UInt32 evtClass = GetEventClass (event); | ||
1858 | UInt32 evtKind = GetEventKind (event); | ||
1859 | |||
1860 | // Always handle command events, even in hands-off mode. | ||
1861 | if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess)) | ||
1862 | { | ||
1863 | HICommand command; | ||
1864 | GetEventParameter (event, kEventParamDirectObject, typeHICommand, NULL, sizeof(command), NULL, &command); | ||
1865 | |||
1866 | switch(command.commandID) | ||
1867 | { | ||
1868 | case kHICommandQuit: | ||
1869 | if(mCallbacks->handleCloseRequest(this)) | ||
1870 | { | ||
1871 | // Get the app to initiate cleanup. | ||
1872 | mCallbacks->handleQuit(this); | ||
1873 | // The app is responsible for calling destroyWindow when done with GL | ||
1874 | } | ||
1875 | result = noErr; | ||
1876 | break; | ||
1877 | |||
1878 | default: | ||
1879 | // MBW -- XXX -- Should we handle other events here? | ||
1880 | break; | ||
1881 | } | ||
1882 | } | ||
1883 | |||
1884 | if(mHandsOffEvents) | ||
1885 | { | ||
1886 | return(result); | ||
1887 | } | ||
1888 | |||
1889 | switch (evtClass) | ||
1890 | { | ||
1891 | case kEventClassTextInput: | ||
1892 | { | ||
1893 | switch (evtKind) | ||
1894 | { | ||
1895 | case kEventTextInputUnicodeForKeyEvent: | ||
1896 | { | ||
1897 | UInt32 modifiers = 0; | ||
1898 | |||
1899 | // First, process the raw event. | ||
1900 | { | ||
1901 | EventRef rawEvent; | ||
1902 | |||
1903 | // Get the original event and extract the modifier keys, so we can ignore command-key events. | ||
1904 | if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr) | ||
1905 | { | ||
1906 | // Grab the modifiers for later use in this function... | ||
1907 | GetEventParameter (rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); | ||
1908 | |||
1909 | // and call this function recursively to handle the raw key event. | ||
1910 | eventHandler (myHandler, rawEvent); | ||
1911 | } | ||
1912 | } | ||
1913 | |||
1914 | OSStatus err = noErr; | ||
1915 | EventParamType actualType = typeUnicodeText; | ||
1916 | UInt32 actualSize = 0; | ||
1917 | size_t actualCount = 0; | ||
1918 | U16 *buffer = NULL; | ||
1919 | |||
1920 | // Get the size of the unicode data | ||
1921 | err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, 0, &actualSize, NULL); | ||
1922 | if(err == noErr) | ||
1923 | { | ||
1924 | // allocate a buffer and get the actual data. | ||
1925 | actualCount = actualSize / sizeof(U16); | ||
1926 | buffer = new U16[actualCount]; | ||
1927 | err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, actualSize, &actualSize, buffer); | ||
1928 | } | ||
1929 | |||
1930 | if(err == noErr) | ||
1931 | { | ||
1932 | if(modifiers & (cmdKey | controlKey)) | ||
1933 | { | ||
1934 | // This was a menu key equivalent. Ignore it. | ||
1935 | } | ||
1936 | else | ||
1937 | { | ||
1938 | MASK mask = 0; | ||
1939 | if(modifiers & shiftKey) { mask |= MASK_SHIFT; } | ||
1940 | if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } | ||
1941 | if(modifiers & optionKey) { mask |= MASK_ALT; } | ||
1942 | |||
1943 | llassert( actualType == typeUnicodeText ); | ||
1944 | |||
1945 | // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar. | ||
1946 | |||
1947 | // Convert to UTF32 and go character-by-character. | ||
1948 | llutf16string utf16(buffer, actualCount); | ||
1949 | LLWString utf32 = utf16str_to_wstring(utf16); | ||
1950 | LLWString::iterator iter; | ||
1951 | |||
1952 | for(iter = utf32.begin(); iter != utf32.end(); iter++) | ||
1953 | { | ||
1954 | mCallbacks->handleUnicodeChar(*iter, mask); | ||
1955 | } | ||
1956 | } | ||
1957 | } | ||
1958 | |||
1959 | if(buffer != NULL) | ||
1960 | { | ||
1961 | delete[] buffer; | ||
1962 | } | ||
1963 | |||
1964 | result = err; | ||
1965 | } | ||
1966 | break; | ||
1967 | } | ||
1968 | } | ||
1969 | break; | ||
1970 | |||
1971 | case kEventClassKeyboard: | ||
1972 | { | ||
1973 | UInt32 keyCode = 0; | ||
1974 | char charCode = 0; | ||
1975 | UInt32 modifiers = 0; | ||
1976 | |||
1977 | // Some of these may fail for some event types. That's fine. | ||
1978 | GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); | ||
1979 | GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); | ||
1980 | |||
1981 | // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers); | ||
1982 | // fflush(stdout); | ||
1983 | |||
1984 | switch (evtKind) | ||
1985 | { | ||
1986 | case kEventRawKeyDown: | ||
1987 | case kEventRawKeyRepeat: | ||
1988 | if (gDebugWindowProc) | ||
1989 | { | ||
1990 | printf("key down, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", | ||
1991 | (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers); | ||
1992 | fflush(stdout); | ||
1993 | } | ||
1994 | gKeyboard->handleKeyDown(keyCode, modifiers); | ||
1995 | result = eventNotHandledErr; | ||
1996 | break; | ||
1997 | |||
1998 | case kEventRawKeyUp: | ||
1999 | if (gDebugWindowProc) | ||
2000 | { | ||
2001 | printf("key up, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", | ||
2002 | (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers); | ||
2003 | fflush(stdout); | ||
2004 | } | ||
2005 | gKeyboard->handleKeyUp(keyCode, modifiers); | ||
2006 | result = eventNotHandledErr; | ||
2007 | break; | ||
2008 | |||
2009 | case kEventRawKeyModifiersChanged: | ||
2010 | // The keyboard input system wants key up/down events for modifier keys. | ||
2011 | // Mac OS doesn't supply these directly, but can supply events when the collective modifier state changes. | ||
2012 | // Use these events to generate up/down events for the modifiers. | ||
2013 | |||
2014 | if((modifiers & shiftKey) && !(mLastModifiers & shiftKey)) | ||
2015 | { | ||
2016 | if (gDebugWindowProc) printf("Shift key down event\n"); | ||
2017 | gKeyboard->handleKeyDown(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000)); | ||
2018 | } | ||
2019 | else if(!(modifiers & shiftKey) && (mLastModifiers & shiftKey)) | ||
2020 | { | ||
2021 | if (gDebugWindowProc) printf("Shift key up event\n"); | ||
2022 | gKeyboard->handleKeyUp(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000)); | ||
2023 | } | ||
2024 | |||
2025 | if((modifiers & alphaLock) && !(mLastModifiers & alphaLock)) | ||
2026 | { | ||
2027 | if (gDebugWindowProc) printf("Caps lock down event\n"); | ||
2028 | gKeyboard->handleKeyDown(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000)); | ||
2029 | } | ||
2030 | else if(!(modifiers & alphaLock) && (mLastModifiers & alphaLock)) | ||
2031 | { | ||
2032 | if (gDebugWindowProc) printf("Caps lock up event\n"); | ||
2033 | gKeyboard->handleKeyUp(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000)); | ||
2034 | } | ||
2035 | |||
2036 | if((modifiers & controlKey) && !(mLastModifiers & controlKey)) | ||
2037 | { | ||
2038 | if (gDebugWindowProc) printf("Control key down event\n"); | ||
2039 | gKeyboard->handleKeyDown(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000)); | ||
2040 | } | ||
2041 | else if(!(modifiers & controlKey) && (mLastModifiers & controlKey)) | ||
2042 | { | ||
2043 | if (gDebugWindowProc) printf("Control key up event\n"); | ||
2044 | gKeyboard->handleKeyUp(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000)); | ||
2045 | } | ||
2046 | |||
2047 | if((modifiers & optionKey) && !(mLastModifiers & optionKey)) | ||
2048 | { | ||
2049 | if (gDebugWindowProc) printf("Option key down event\n"); | ||
2050 | gKeyboard->handleKeyDown(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000)); | ||
2051 | } | ||
2052 | else if(!(modifiers & optionKey) && (mLastModifiers & optionKey)) | ||
2053 | { | ||
2054 | if (gDebugWindowProc) printf("Option key up event\n"); | ||
2055 | gKeyboard->handleKeyUp(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000)); | ||
2056 | } | ||
2057 | |||
2058 | // When the state of the 'Fn' key (the one that changes some of the mappings on a powerbook/macbook keyboard | ||
2059 | // to an embedded keypad) changes, it may subsequently cause a key up event to be lost, which may lead to | ||
2060 | // a movement key getting "stuck" down. This is bad. | ||
2061 | // This is an OS bug -- even the GetKeys() API doesn't tell you the key has been released. | ||
2062 | // This workaround causes all held-down keys to be reset whenever the state of the Fn key changes. This isn't | ||
2063 | // exactly what we want, but it does avoid the case where you get stuck running forward. | ||
2064 | if((modifiers & kEventKeyModifierFnMask) != (mLastModifiers & kEventKeyModifierFnMask)) | ||
2065 | { | ||
2066 | if (gDebugWindowProc) printf("Fn key state change event\n"); | ||
2067 | gKeyboard->resetKeys(); | ||
2068 | } | ||
2069 | |||
2070 | if (gDebugWindowProc) fflush(stdout); | ||
2071 | |||
2072 | mLastModifiers = modifiers; | ||
2073 | result = eventNotHandledErr; | ||
2074 | break; | ||
2075 | } | ||
2076 | } | ||
2077 | break; | ||
2078 | |||
2079 | case kEventClassMouse: | ||
2080 | { | ||
2081 | result = CallNextEventHandler(myHandler, event); | ||
2082 | if (eventNotHandledErr == result) | ||
2083 | { // only handle events not already handled (prevents wierd resize interaction) | ||
2084 | EventMouseButton button = kEventMouseButtonPrimary; | ||
2085 | HIPoint location = {0.0f, 0.0f}; | ||
2086 | UInt32 modifiers = 0; | ||
2087 | UInt32 clickCount = 1; | ||
2088 | long wheelDelta = 0; | ||
2089 | LLCoordScreen inCoords; | ||
2090 | LLCoordGL outCoords; | ||
2091 | MASK mask = 0; | ||
2092 | |||
2093 | GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); | ||
2094 | GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(location), NULL, &location); | ||
2095 | GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers); | ||
2096 | GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(wheelDelta), NULL, &wheelDelta); | ||
2097 | GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount); | ||
2098 | |||
2099 | inCoords.mX = llround(location.x); | ||
2100 | inCoords.mY = llround(location.y); | ||
2101 | |||
2102 | if(modifiers & shiftKey) { mask |= MASK_SHIFT; } | ||
2103 | if(modifiers & controlKey) { mask |= MASK_CONTROL; } | ||
2104 | if(modifiers & optionKey) { mask |= MASK_ALT; } | ||
2105 | |||
2106 | if(mCursorDecoupled) | ||
2107 | { | ||
2108 | CGMouseDelta x, y; | ||
2109 | |||
2110 | // If the cursor's decoupled, we need to read the latest movement delta as well. | ||
2111 | CGGetLastMouseDelta( &x, &y ); | ||
2112 | mCursorLastEventDeltaX = x; | ||
2113 | mCursorLastEventDeltaY = y; | ||
2114 | |||
2115 | if(mCursorIgnoreNextDelta) | ||
2116 | { | ||
2117 | mCursorLastEventDeltaX = 0; | ||
2118 | mCursorLastEventDeltaY = 0; | ||
2119 | mCursorIgnoreNextDelta = FALSE; | ||
2120 | } | ||
2121 | } | ||
2122 | else | ||
2123 | { | ||
2124 | mCursorLastEventDeltaX = 0; | ||
2125 | mCursorLastEventDeltaY = 0; | ||
2126 | } | ||
2127 | |||
2128 | inCoords.mX += mCursorLastEventDeltaX; | ||
2129 | inCoords.mY += mCursorLastEventDeltaY; | ||
2130 | |||
2131 | convertCoords(inCoords, &outCoords); | ||
2132 | |||
2133 | // printf("coords in: %d, %d; coords out: %d, %d\n", inCoords.mX, inCoords.mY, outCoords.mX, outCoords.mY); | ||
2134 | // fflush(stdout); | ||
2135 | |||
2136 | |||
2137 | switch (evtKind) | ||
2138 | { | ||
2139 | case kEventMouseDown: | ||
2140 | switch(button) | ||
2141 | { | ||
2142 | case kEventMouseButtonPrimary: | ||
2143 | if(modifiers & cmdKey) | ||
2144 | { | ||
2145 | // Simulate a right click | ||
2146 | mSimulatedRightClick = true; | ||
2147 | mCallbacks->handleRightMouseDown(this, outCoords, mask); | ||
2148 | } | ||
2149 | else if(clickCount == 2) | ||
2150 | { | ||
2151 | // Windows double-click events replace the second mousedown event in a double-click. | ||
2152 | mCallbacks->handleDoubleClick(this, outCoords, mask); | ||
2153 | } | ||
2154 | else | ||
2155 | { | ||
2156 | mCallbacks->handleMouseDown(this, outCoords, mask); | ||
2157 | } | ||
2158 | break; | ||
2159 | case kEventMouseButtonSecondary: | ||
2160 | mCallbacks->handleRightMouseDown(this, outCoords, mask); | ||
2161 | break; | ||
2162 | } | ||
2163 | result = noErr; | ||
2164 | break; | ||
2165 | case kEventMouseUp: | ||
2166 | |||
2167 | switch(button) | ||
2168 | { | ||
2169 | case kEventMouseButtonPrimary: | ||
2170 | if(mSimulatedRightClick) | ||
2171 | { | ||
2172 | // End of simulated right click | ||
2173 | mSimulatedRightClick = false; | ||
2174 | mCallbacks->handleRightMouseUp(this, outCoords, mask); | ||
2175 | } | ||
2176 | else | ||
2177 | { | ||
2178 | mCallbacks->handleMouseUp(this, outCoords, mask); | ||
2179 | } | ||
2180 | break; | ||
2181 | case kEventMouseButtonSecondary: | ||
2182 | mCallbacks->handleRightMouseUp(this, outCoords, mask); | ||
2183 | break; | ||
2184 | } | ||
2185 | result = noErr; | ||
2186 | break; | ||
2187 | |||
2188 | case kEventMouseWheelMoved: | ||
2189 | { | ||
2190 | static S32 z_delta = 0; | ||
2191 | |||
2192 | z_delta += wheelDelta; | ||
2193 | |||
2194 | if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) | ||
2195 | { | ||
2196 | mCallbacks->handleScrollWheel(this, -z_delta / WHEEL_DELTA); | ||
2197 | z_delta = 0; | ||
2198 | } | ||
2199 | } | ||
2200 | result = noErr; | ||
2201 | break; | ||
2202 | |||
2203 | case kEventMouseDragged: | ||
2204 | case kEventMouseMoved: | ||
2205 | mCallbacks->handleMouseMove(this, outCoords, mask); | ||
2206 | result = noErr; | ||
2207 | break; | ||
2208 | |||
2209 | } | ||
2210 | } | ||
2211 | } | ||
2212 | break; | ||
2213 | |||
2214 | case kEventClassWindow: | ||
2215 | switch(evtKind) | ||
2216 | { | ||
2217 | case kEventWindowBoundsChanging: | ||
2218 | { | ||
2219 | Rect currentBounds; | ||
2220 | Rect previousBounds; | ||
2221 | |||
2222 | GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds); | ||
2223 | GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &previousBounds); | ||
2224 | |||
2225 | // This is where we would constrain move/resize to a particular screen | ||
2226 | if(0) | ||
2227 | { | ||
2228 | SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), ¤tBounds); | ||
2229 | } | ||
2230 | } | ||
2231 | break; | ||
2232 | |||
2233 | case kEventWindowBoundsChanged: | ||
2234 | { | ||
2235 | Rect newBounds; | ||
2236 | |||
2237 | GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &newBounds); | ||
2238 | aglUpdateContext(mContext); | ||
2239 | mCallbacks->handleResize(this, newBounds.right - newBounds.left, newBounds.bottom - newBounds.top); | ||
2240 | |||
2241 | |||
2242 | } | ||
2243 | break; | ||
2244 | |||
2245 | case kEventWindowClose: | ||
2246 | if(mCallbacks->handleCloseRequest(this)) | ||
2247 | { | ||
2248 | // Get the app to initiate cleanup. | ||
2249 | mCallbacks->handleQuit(this); | ||
2250 | // The app is responsible for calling destroyWindow when done with GL | ||
2251 | } | ||
2252 | result = noErr; | ||
2253 | break; | ||
2254 | |||
2255 | case kEventWindowHidden: | ||
2256 | // llinfos << "LLWindowMacOSX: Deactivating on hide" << llendl; | ||
2257 | mMinimized = TRUE; | ||
2258 | mCallbacks->handleActivate(this, false); | ||
2259 | // result = noErr; | ||
2260 | break; | ||
2261 | |||
2262 | case kEventWindowShown: | ||
2263 | // llinfos << "LLWindowMacOSX: Activating on show" << llendl; | ||
2264 | mMinimized = FALSE; | ||
2265 | mCallbacks->handleActivate(this, true); | ||
2266 | // result = noErr; | ||
2267 | break; | ||
2268 | |||
2269 | case kEventWindowCollapsed: | ||
2270 | // llinfos << "LLWindowMacOSX: Deactivating on collapse" << llendl; | ||
2271 | mMinimized = TRUE; | ||
2272 | mCallbacks->handleActivate(this, false); | ||
2273 | // result = noErr; | ||
2274 | break; | ||
2275 | |||
2276 | case kEventWindowExpanded: | ||
2277 | // llinfos << "LLWindowMacOSX: Activating on expand" << llendl; | ||
2278 | mMinimized = FALSE; | ||
2279 | mCallbacks->handleActivate(this, true); | ||
2280 | // result = noErr; | ||
2281 | break; | ||
2282 | |||
2283 | case kEventWindowGetClickActivation: | ||
2284 | // BringToFront(mWindow); | ||
2285 | // result = noErr; | ||
2286 | break; | ||
2287 | } | ||
2288 | break; | ||
2289 | } | ||
2290 | return result; | ||
2291 | } | ||
2292 | |||
2293 | const char* cursorIDToName(int id) | ||
2294 | { | ||
2295 | switch (id) | ||
2296 | { | ||
2297 | case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; | ||
2298 | case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; | ||
2299 | case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; | ||
2300 | case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; | ||
2301 | case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; | ||
2302 | case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; | ||
2303 | case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; | ||
2304 | case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; | ||
2305 | case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; | ||
2306 | case UI_CURSOR_NO: return "UI_CURSOR_NO"; | ||
2307 | case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; | ||
2308 | case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; | ||
2309 | case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; | ||
2310 | case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; | ||
2311 | case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; | ||
2312 | case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; | ||
2313 | case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; | ||
2314 | case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; | ||
2315 | case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; | ||
2316 | case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; | ||
2317 | case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; | ||
2318 | case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; | ||
2319 | case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; | ||
2320 | case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; | ||
2321 | case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; | ||
2322 | case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; | ||
2323 | case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; | ||
2324 | case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; | ||
2325 | case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; | ||
2326 | case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; | ||
2327 | case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; | ||
2328 | case UI_CURSOR_TOOLPAY: return "UI_CURSOR_TOOLPAY"; | ||
2329 | case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; | ||
2330 | case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; | ||
2331 | } | ||
2332 | |||
2333 | llerrs << "cursorIDToName: unknown cursor id" << id << llendl; | ||
2334 | |||
2335 | return "UI_CURSOR_ARROW"; | ||
2336 | } | ||
2337 | |||
2338 | static CursorRef gCursors[UI_CURSOR_COUNT]; | ||
2339 | |||
2340 | |||
2341 | static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) | ||
2342 | { | ||
2343 | // cursors are in <Application Bundle>/Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif | ||
2344 | std::string fullpath = gDirUtilp->getAppRODataDir(); | ||
2345 | fullpath += gDirUtilp->getDirDelimiter(); | ||
2346 | fullpath += "cursors_mac"; | ||
2347 | fullpath += gDirUtilp->getDirDelimiter(); | ||
2348 | fullpath += cursorIDToName(cursorid); | ||
2349 | fullpath += ".tif"; | ||
2350 | |||
2351 | gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); | ||
2352 | } | ||
2353 | |||
2354 | void LLWindowMacOSX::setCursor(ECursorType cursor) | ||
2355 | { | ||
2356 | OSStatus result = noErr; | ||
2357 | |||
2358 | if (cursor == UI_CURSOR_ARROW | ||
2359 | && mBusyCount > 0) | ||
2360 | { | ||
2361 | cursor = UI_CURSOR_WORKING; | ||
2362 | } | ||
2363 | |||
2364 | if(mCurrentCursor == cursor) | ||
2365 | return; | ||
2366 | |||
2367 | // RN: replace multi-drag cursors with single versions | ||
2368 | if (cursor == UI_CURSOR_ARROWDRAGMULTI) | ||
2369 | { | ||
2370 | cursor = UI_CURSOR_ARROWDRAG; | ||
2371 | } | ||
2372 | else if (cursor == UI_CURSOR_ARROWCOPYMULTI) | ||
2373 | { | ||
2374 | cursor = UI_CURSOR_ARROWCOPY; | ||
2375 | } | ||
2376 | |||
2377 | switch(cursor) | ||
2378 | { | ||
2379 | default: | ||
2380 | case UI_CURSOR_ARROW: | ||
2381 | InitCursor(); | ||
2382 | if(mCursorHidden) | ||
2383 | { | ||
2384 | // Since InitCursor resets the hide level, correct for it here. | ||
2385 | ::HideCursor(); | ||
2386 | } | ||
2387 | break; | ||
2388 | |||
2389 | // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. | ||
2390 | // Find out what they look like and replicate them. | ||
2391 | |||
2392 | // These are essentially correct | ||
2393 | case UI_CURSOR_WAIT: SetThemeCursor(kThemeWatchCursor); break; | ||
2394 | case UI_CURSOR_IBEAM: SetThemeCursor(kThemeIBeamCursor); break; | ||
2395 | case UI_CURSOR_CROSS: SetThemeCursor(kThemeCrossCursor); break; | ||
2396 | case UI_CURSOR_HAND: SetThemeCursor(kThemePointingHandCursor); break; | ||
2397 | // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; | ||
2398 | case UI_CURSOR_ARROWCOPY: SetThemeCursor(kThemeCopyArrowCursor); break; | ||
2399 | |||
2400 | // Double-check these | ||
2401 | case UI_CURSOR_NO: | ||
2402 | case UI_CURSOR_SIZEWE: | ||
2403 | case UI_CURSOR_SIZENS: | ||
2404 | case UI_CURSOR_SIZENWSE: | ||
2405 | case UI_CURSOR_SIZENESW: | ||
2406 | case UI_CURSOR_WORKING: | ||
2407 | case UI_CURSOR_TOOLGRAB: | ||
2408 | case UI_CURSOR_TOOLLAND: | ||
2409 | case UI_CURSOR_TOOLFOCUS: | ||
2410 | case UI_CURSOR_TOOLCREATE: | ||
2411 | case UI_CURSOR_ARROWDRAG: | ||
2412 | case UI_CURSOR_NOLOCKED: | ||
2413 | case UI_CURSOR_ARROWLOCKED: | ||
2414 | case UI_CURSOR_GRABLOCKED: | ||
2415 | case UI_CURSOR_TOOLTRANSLATE: | ||
2416 | case UI_CURSOR_TOOLROTATE: | ||
2417 | case UI_CURSOR_TOOLSCALE: | ||
2418 | case UI_CURSOR_TOOLCAMERA: | ||
2419 | case UI_CURSOR_TOOLPAN: | ||
2420 | case UI_CURSOR_TOOLZOOMIN: | ||
2421 | case UI_CURSOR_TOOLPICKOBJECT3: | ||
2422 | case UI_CURSOR_TOOLSIT: | ||
2423 | case UI_CURSOR_TOOLBUY: | ||
2424 | case UI_CURSOR_TOOLPAY: | ||
2425 | case UI_CURSOR_TOOLOPEN: | ||
2426 | result = setImageCursor(gCursors[cursor]); | ||
2427 | break; | ||
2428 | |||
2429 | } | ||
2430 | |||
2431 | if(result != noErr) | ||
2432 | { | ||
2433 | InitCursor(); | ||
2434 | } | ||
2435 | |||
2436 | mCurrentCursor = cursor; | ||
2437 | } | ||
2438 | |||
2439 | ECursorType LLWindowMacOSX::getCursor() | ||
2440 | { | ||
2441 | return mCurrentCursor; | ||
2442 | } | ||
2443 | |||
2444 | void LLWindowMacOSX::initCursors() | ||
2445 | { | ||
2446 | initPixmapCursor(UI_CURSOR_NO, 8, 8); | ||
2447 | initPixmapCursor(UI_CURSOR_WORKING, 1, 1); | ||
2448 | initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); | ||
2449 | initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); | ||
2450 | initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); | ||
2451 | initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); | ||
2452 | initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); | ||
2453 | initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); | ||
2454 | initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); | ||
2455 | initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); | ||
2456 | initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); | ||
2457 | initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); | ||
2458 | initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); | ||
2459 | initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); | ||
2460 | initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); | ||
2461 | initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); | ||
2462 | initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); | ||
2463 | initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); | ||
2464 | initPixmapCursor(UI_CURSOR_TOOLSIT, 1, 1); | ||
2465 | initPixmapCursor(UI_CURSOR_TOOLBUY, 1, 1); | ||
2466 | initPixmapCursor(UI_CURSOR_TOOLPAY, 1, 1); | ||
2467 | initPixmapCursor(UI_CURSOR_TOOLOPEN, 1, 1); | ||
2468 | |||
2469 | initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); | ||
2470 | initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); | ||
2471 | initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); | ||
2472 | initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); | ||
2473 | |||
2474 | } | ||
2475 | |||
2476 | void LLWindowMacOSX::captureMouse() | ||
2477 | { | ||
2478 | // By registering a global CarbonEvent handler for mouse move events, we ensure that | ||
2479 | // mouse events are always processed. Thus, capture and release are unnecessary. | ||
2480 | } | ||
2481 | |||
2482 | void LLWindowMacOSX::releaseMouse() | ||
2483 | { | ||
2484 | // By registering a global CarbonEvent handler for mouse move events, we ensure that | ||
2485 | // mouse events are always processed. Thus, capture and release are unnecessary. | ||
2486 | } | ||
2487 | |||
2488 | void LLWindowMacOSX::hideCursor() | ||
2489 | { | ||
2490 | if(!mCursorHidden) | ||
2491 | { | ||
2492 | // llinfos << "hideCursor: hiding" << llendl; | ||
2493 | mCursorHidden = TRUE; | ||
2494 | mHideCursorPermanent = TRUE; | ||
2495 | ::HideCursor(); | ||
2496 | } | ||
2497 | else | ||
2498 | { | ||
2499 | // llinfos << "hideCursor: already hidden" << llendl; | ||
2500 | } | ||
2501 | |||
2502 | adjustCursorDecouple(); | ||
2503 | } | ||
2504 | |||
2505 | void LLWindowMacOSX::showCursor() | ||
2506 | { | ||
2507 | if(mCursorHidden) | ||
2508 | { | ||
2509 | // llinfos << "showCursor: showing" << llendl; | ||
2510 | mCursorHidden = FALSE; | ||
2511 | mHideCursorPermanent = FALSE; | ||
2512 | ::ShowCursor(); | ||
2513 | } | ||
2514 | else | ||
2515 | { | ||
2516 | // llinfos << "showCursor: already visible" << llendl; | ||
2517 | } | ||
2518 | |||
2519 | adjustCursorDecouple(); | ||
2520 | } | ||
2521 | |||
2522 | void LLWindowMacOSX::showCursorFromMouseMove() | ||
2523 | { | ||
2524 | if (!mHideCursorPermanent) | ||
2525 | { | ||
2526 | showCursor(); | ||
2527 | } | ||
2528 | } | ||
2529 | |||
2530 | void LLWindowMacOSX::hideCursorUntilMouseMove() | ||
2531 | { | ||
2532 | if (!mHideCursorPermanent) | ||
2533 | { | ||
2534 | hideCursor(); | ||
2535 | mHideCursorPermanent = FALSE; | ||
2536 | } | ||
2537 | } | ||
2538 | |||
2539 | |||
2540 | |||
2541 | // | ||
2542 | // LLSplashScreenMacOSX | ||
2543 | // | ||
2544 | LLSplashScreenMacOSX::LLSplashScreenMacOSX() | ||
2545 | { | ||
2546 | mWindow = NULL; | ||
2547 | } | ||
2548 | |||
2549 | LLSplashScreenMacOSX::~LLSplashScreenMacOSX() | ||
2550 | { | ||
2551 | } | ||
2552 | |||
2553 | void LLSplashScreenMacOSX::showImpl() | ||
2554 | { | ||
2555 | // This code _could_ be used to display a spash screen... | ||
2556 | #if 0 | ||
2557 | IBNibRef nib = NULL; | ||
2558 | OSStatus err; | ||
2559 | |||
2560 | err = CreateNibReference(CFSTR("SecondLife"), &nib); | ||
2561 | |||
2562 | if(err == noErr) | ||
2563 | { | ||
2564 | CreateWindowFromNib(nib, CFSTR("Splash Screen"), &mWindow); | ||
2565 | |||
2566 | DisposeNibReference(nib); | ||
2567 | } | ||
2568 | |||
2569 | if(mWindow != NULL) | ||
2570 | { | ||
2571 | ShowWindow(mWindow); | ||
2572 | } | ||
2573 | #endif | ||
2574 | } | ||
2575 | |||
2576 | void LLSplashScreenMacOSX::updateImpl(const char* mesg) | ||
2577 | { | ||
2578 | if(mWindow != NULL) | ||
2579 | { | ||
2580 | CFStringRef string = NULL; | ||
2581 | |||
2582 | if(mesg != NULL) | ||
2583 | { | ||
2584 | string = CFStringCreateWithCString(NULL, mesg, kCFStringEncodingUTF8); | ||
2585 | } | ||
2586 | else | ||
2587 | { | ||
2588 | string = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); | ||
2589 | } | ||
2590 | |||
2591 | if(string != NULL) | ||
2592 | { | ||
2593 | ControlRef progressText = NULL; | ||
2594 | ControlID id; | ||
2595 | OSStatus err; | ||
2596 | |||
2597 | id.signature = 'what'; | ||
2598 | id.id = 0; | ||
2599 | |||
2600 | err = GetControlByID(mWindow, &id, &progressText); | ||
2601 | if(err == noErr) | ||
2602 | { | ||
2603 | err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&string); | ||
2604 | Draw1Control(progressText); | ||
2605 | } | ||
2606 | |||
2607 | CFRelease(string); | ||
2608 | } | ||
2609 | } | ||
2610 | } | ||
2611 | |||
2612 | |||
2613 | void LLSplashScreenMacOSX::hideImpl() | ||
2614 | { | ||
2615 | if(mWindow != NULL) | ||
2616 | { | ||
2617 | DisposeWindow(mWindow); | ||
2618 | mWindow = NULL; | ||
2619 | } | ||
2620 | } | ||
2621 | |||
2622 | |||
2623 | |||
2624 | S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type) | ||
2625 | { | ||
2626 | S32 result = OSBTN_CANCEL; | ||
2627 | SInt16 retval_mac = 1; | ||
2628 | AlertStdCFStringAlertParamRec params; | ||
2629 | CFStringRef errorString = NULL; | ||
2630 | CFStringRef explanationString = NULL; | ||
2631 | DialogRef alert = NULL; | ||
2632 | AlertType alertType = kAlertCautionAlert; | ||
2633 | OSStatus err; | ||
2634 | |||
2635 | if(text != NULL) | ||
2636 | { | ||
2637 | explanationString = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); | ||
2638 | } | ||
2639 | else | ||
2640 | { | ||
2641 | explanationString = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); | ||
2642 | } | ||
2643 | |||
2644 | if(caption != NULL) | ||
2645 | { | ||
2646 | errorString = CFStringCreateWithCString(NULL, caption, kCFStringEncodingUTF8); | ||
2647 | } | ||
2648 | else | ||
2649 | { | ||
2650 | errorString = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); | ||
2651 | } | ||
2652 | |||
2653 | params.version = kStdCFStringAlertVersionOne; | ||
2654 | params.movable = false; | ||
2655 | params.helpButton = false; | ||
2656 | params.defaultText = (CFStringRef)kAlertDefaultOKText; | ||
2657 | params.cancelText = 0; | ||
2658 | params.otherText = 0; | ||
2659 | params.defaultButton = 1; | ||
2660 | params.cancelButton = 0; | ||
2661 | params.position = kWindowDefaultPosition; | ||
2662 | params.flags = 0; | ||
2663 | |||
2664 | switch(type) | ||
2665 | { | ||
2666 | case OSMB_OK: | ||
2667 | default: | ||
2668 | break; | ||
2669 | case OSMB_OKCANCEL: | ||
2670 | params.cancelText = (CFStringRef)kAlertDefaultCancelText; | ||
2671 | params.cancelButton = 2; | ||
2672 | break; | ||
2673 | case OSMB_YESNO: | ||
2674 | alertType = kAlertNoteAlert; | ||
2675 | params.defaultText = CFSTR("Yes"); | ||
2676 | params.cancelText = CFSTR("No"); | ||
2677 | params.cancelButton = 2; | ||
2678 | break; | ||
2679 | } | ||
2680 | |||
2681 | if(gWindowImplementation != NULL) | ||
2682 | gWindowImplementation->beforeDialog(); | ||
2683 | |||
2684 | err = CreateStandardAlert( | ||
2685 | alertType, | ||
2686 | errorString, | ||
2687 | explanationString, | ||
2688 | ¶ms, | ||
2689 | &alert); | ||
2690 | |||
2691 | if(err == noErr) | ||
2692 | { | ||
2693 | err = RunStandardAlert( | ||
2694 | alert, | ||
2695 | NULL, | ||
2696 | &retval_mac); | ||
2697 | } | ||
2698 | |||
2699 | if(gWindowImplementation != NULL) | ||
2700 | gWindowImplementation->afterDialog(); | ||
2701 | |||
2702 | switch(type) | ||
2703 | { | ||
2704 | case OSMB_OK: | ||
2705 | case OSMB_OKCANCEL: | ||
2706 | default: | ||
2707 | if(retval_mac == 1) | ||
2708 | result = OSBTN_OK; | ||
2709 | else | ||
2710 | result = OSBTN_CANCEL; | ||
2711 | break; | ||
2712 | case OSMB_YESNO: | ||
2713 | if(retval_mac == 1) | ||
2714 | result = OSBTN_YES; | ||
2715 | else | ||
2716 | result = OSBTN_NO; | ||
2717 | break; | ||
2718 | } | ||
2719 | |||
2720 | if(errorString != NULL) | ||
2721 | { | ||
2722 | CFRelease(errorString); | ||
2723 | } | ||
2724 | |||
2725 | if(explanationString != NULL) | ||
2726 | { | ||
2727 | CFRelease(explanationString); | ||
2728 | } | ||
2729 | |||
2730 | return result; | ||
2731 | } | ||
2732 | |||
2733 | // Open a URL with the user's default web browser. | ||
2734 | // Must begin with protocol identifier. | ||
2735 | void spawn_web_browser(const char* escaped_url) | ||
2736 | { | ||
2737 | bool found = false; | ||
2738 | S32 i; | ||
2739 | for (i = 0; i < gURLProtocolWhitelistCount; i++) | ||
2740 | { | ||
2741 | S32 len = strlen(gURLProtocolWhitelist[i]); | ||
2742 | if (!strncmp(escaped_url, gURLProtocolWhitelist[i], len) | ||
2743 | && escaped_url[len] == ':') | ||
2744 | { | ||
2745 | found = true; | ||
2746 | break; | ||
2747 | } | ||
2748 | } | ||
2749 | |||
2750 | if (!found) | ||
2751 | { | ||
2752 | llwarns << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << llendl; | ||
2753 | return; | ||
2754 | } | ||
2755 | |||
2756 | OSStatus result = noErr; | ||
2757 | CFURLRef urlRef = NULL; | ||
2758 | |||
2759 | llinfos << "Opening URL " << escaped_url << llendl; | ||
2760 | |||
2761 | CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url, kCFStringEncodingUTF8); | ||
2762 | if (stringRef) | ||
2763 | { | ||
2764 | // This will succeed if the string is a full URL, including the http:// | ||
2765 | // Note that URLs specified this way need to be properly percent-escaped. | ||
2766 | urlRef = CFURLCreateWithString(NULL, stringRef, NULL); | ||
2767 | |||
2768 | // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs | ||
2769 | |||
2770 | CFRelease(stringRef); | ||
2771 | } | ||
2772 | |||
2773 | if (urlRef) | ||
2774 | { | ||
2775 | result = LSOpenCFURLRef(urlRef, NULL); | ||
2776 | |||
2777 | if (result != noErr) | ||
2778 | { | ||
2779 | llinfos << "Error " << result << " on open." << llendl; | ||
2780 | } | ||
2781 | |||
2782 | CFRelease(urlRef); | ||
2783 | } | ||
2784 | else | ||
2785 | { | ||
2786 | llinfos << "Error: couldn't create URL." << llendl; | ||
2787 | } | ||
2788 | } | ||
2789 | |||
2790 | void shell_open( const char* file_path ) | ||
2791 | { | ||
2792 | OSStatus result = noErr; | ||
2793 | |||
2794 | llinfos << "Opening " << file_path << llendl; | ||
2795 | CFURLRef urlRef = NULL; | ||
2796 | |||
2797 | CFStringRef stringRef = CFStringCreateWithCString(NULL, file_path, kCFStringEncodingUTF8); | ||
2798 | if (stringRef) | ||
2799 | { | ||
2800 | // This will succeed if the string is a full URL, including the http:// | ||
2801 | // Note that URLs specified this way need to be properly percent-escaped. | ||
2802 | urlRef = CFURLCreateWithString(NULL, stringRef, NULL); | ||
2803 | |||
2804 | if(urlRef == NULL) | ||
2805 | { | ||
2806 | // This will succeed if the string is a full or partial posix path. | ||
2807 | // This will work even if the path contains characters that would need to be percent-escaped | ||
2808 | // in the URL (such as spaces). | ||
2809 | urlRef = CFURLCreateWithFileSystemPath(NULL, stringRef, kCFURLPOSIXPathStyle, false); | ||
2810 | } | ||
2811 | |||
2812 | CFRelease(stringRef); | ||
2813 | } | ||
2814 | |||
2815 | if (urlRef) | ||
2816 | { | ||
2817 | result = LSOpenCFURLRef(urlRef, NULL); | ||
2818 | |||
2819 | if (result != noErr) | ||
2820 | { | ||
2821 | llinfos << "Error " << result << " on open." << llendl; | ||
2822 | } | ||
2823 | CFRelease(urlRef); | ||
2824 | } | ||
2825 | else | ||
2826 | { | ||
2827 | llinfos << "Error: couldn't create URL." << llendl; | ||
2828 | } | ||
2829 | } | ||
2830 | |||
2831 | BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b) | ||
2832 | { | ||
2833 | BOOL retval = FALSE; | ||
2834 | OSErr error = noErr; | ||
2835 | NColorPickerInfo info; | ||
2836 | |||
2837 | memset(&info, 0, sizeof(info)); | ||
2838 | info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); | ||
2839 | info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); | ||
2840 | info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); | ||
2841 | info.placeWhere = kCenterOnMainScreen; | ||
2842 | |||
2843 | if(gWindowImplementation != NULL) | ||
2844 | gWindowImplementation->beforeDialog(); | ||
2845 | |||
2846 | error = NPickColor(&info); | ||
2847 | |||
2848 | if(gWindowImplementation != NULL) | ||
2849 | gWindowImplementation->afterDialog(); | ||
2850 | |||
2851 | if (error == noErr) | ||
2852 | { | ||
2853 | retval = info.newColorChosen; | ||
2854 | if (info.newColorChosen) | ||
2855 | { | ||
2856 | *r = ((float) info.theColor.color.rgb.red) / 65535.0; | ||
2857 | *g = ((float) info.theColor.color.rgb.green) / 65535.0; | ||
2858 | *b = ((float) info.theColor.color.rgb.blue) / 65535.0; | ||
2859 | } | ||
2860 | } | ||
2861 | return (retval); | ||
2862 | } | ||
2863 | |||
2864 | static WindowRef dummywindowref = NULL; | ||
2865 | |||
2866 | void *LLWindowMacOSX::getPlatformWindow() | ||
2867 | { | ||
2868 | if(mWindow != NULL) | ||
2869 | return (void*)mWindow; | ||
2870 | |||
2871 | // If we're in fullscreen mode, there's no window pointer available. | ||
2872 | // Since Mozilla needs one to function, create a dummy window here. | ||
2873 | // Note that we will never destroy it, but since only one will be created per run of the application, that's okay. | ||
2874 | |||
2875 | if(dummywindowref == NULL) | ||
2876 | { | ||
2877 | Rect window_rect = {100, 100, 200, 200}; | ||
2878 | |||
2879 | dummywindowref = NewCWindow( | ||
2880 | NULL, | ||
2881 | &window_rect, | ||
2882 | "\p", | ||
2883 | false, // Create the window invisible. | ||
2884 | zoomDocProc, // Window with a grow box and a zoom box | ||
2885 | kLastWindowOfClass, // create it behind other windows | ||
2886 | false, // no close box | ||
2887 | 0); | ||
2888 | } | ||
2889 | |||
2890 | return (void*)dummywindowref; | ||
2891 | } | ||
2892 | |||
2893 | void LLWindowMacOSX::stopDockTileBounce() | ||
2894 | { | ||
2895 | NMRemove(&mBounceRec); | ||
2896 | mBounceTimer.stop(); | ||
2897 | } | ||
2898 | |||
2899 | // get a double value from a dictionary | ||
2900 | static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) | ||
2901 | { | ||
2902 | double double_value; | ||
2903 | CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); | ||
2904 | if (!number_value) // if can't get a number for the dictionary | ||
2905 | return -1; // fail | ||
2906 | if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it | ||
2907 | return -1; // fail | ||
2908 | return double_value; // otherwise return the long value | ||
2909 | } | ||
2910 | |||
2911 | // get a long value from a dictionary | ||
2912 | static long getDictLong (CFDictionaryRef refDict, CFStringRef key) | ||
2913 | { | ||
2914 | long int_value; | ||
2915 | CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); | ||
2916 | if (!number_value) // if can't get a number for the dictionary | ||
2917 | return -1; // fail | ||
2918 | if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it | ||
2919 | return -1; // fail | ||
2920 | return int_value; // otherwise return the long value | ||
2921 | } | ||
2922 | |||
2923 | #endif // LL_DARWIN | ||
diff --git a/linden/indra/llwindow/llwindowmacosx.h b/linden/indra/llwindow/llwindowmacosx.h new file mode 100644 index 0000000..7425077 --- /dev/null +++ b/linden/indra/llwindow/llwindowmacosx.h | |||
@@ -0,0 +1,208 @@ | |||
1 | /** | ||
2 | * @file llwindowmacosx.h | ||
3 | * @brief Mac implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWMACOSX_H | ||
29 | #define LL_LLWINDOWMACOSX_H | ||
30 | |||
31 | #include "llwindow.h" | ||
32 | |||
33 | #include <Carbon/Carbon.h> | ||
34 | #include <AGL/agl.h> | ||
35 | |||
36 | // AssertMacros.h does bad things. | ||
37 | #undef verify | ||
38 | #undef check | ||
39 | #undef require | ||
40 | |||
41 | |||
42 | class LLWindowMacOSX : public LLWindow | ||
43 | { | ||
44 | public: | ||
45 | /*virtual*/ void show(); | ||
46 | /*virtual*/ void hide(); | ||
47 | /*virtual*/ void close(); | ||
48 | /*virtual*/ BOOL getVisible(); | ||
49 | /*virtual*/ BOOL getMinimized(); | ||
50 | /*virtual*/ BOOL getMaximized(); | ||
51 | /*virtual*/ BOOL maximize(); | ||
52 | /*virtual*/ BOOL getFullscreen(); | ||
53 | /*virtual*/ BOOL getPosition(LLCoordScreen *position); | ||
54 | /*virtual*/ BOOL getSize(LLCoordScreen *size); | ||
55 | /*virtual*/ BOOL getSize(LLCoordWindow *size); | ||
56 | /*virtual*/ BOOL setPosition(LLCoordScreen position); | ||
57 | /*virtual*/ BOOL setSize(LLCoordScreen size); | ||
58 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync); | ||
59 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); | ||
60 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); | ||
61 | /*virtual*/ void showCursor(); | ||
62 | /*virtual*/ void hideCursor(); | ||
63 | /*virtual*/ void showCursorFromMouseMove(); | ||
64 | /*virtual*/ void hideCursorUntilMouseMove(); | ||
65 | /*virtual*/ BOOL isCursorHidden(); | ||
66 | /*virtual*/ void setCursor(ECursorType cursor); | ||
67 | /*virtual*/ ECursorType getCursor(); | ||
68 | /*virtual*/ void captureMouse(); | ||
69 | /*virtual*/ void releaseMouse(); | ||
70 | /*virtual*/ void setMouseClipping( BOOL b ); | ||
71 | /*virtual*/ BOOL isClipboardTextAvailable(); | ||
72 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); | ||
73 | /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); | ||
74 | /*virtual*/ void flashIcon(F32 seconds); | ||
75 | /*virtual*/ F32 getGamma(); | ||
76 | /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma | ||
77 | /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) | ||
78 | /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
79 | /*virtual*/ void gatherInput(); | ||
80 | /*virtual*/ void delayInputProcessing() {}; | ||
81 | /*virtual*/ void swapBuffers(); | ||
82 | |||
83 | /*virtual*/ LLString getTempFileName(); | ||
84 | /*virtual*/ void deleteFile( const char* file_name ); | ||
85 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ); | ||
86 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL); | ||
87 | |||
88 | |||
89 | // handy coordinate space conversion routines | ||
90 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); | ||
91 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); | ||
92 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); | ||
93 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); | ||
94 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); | ||
95 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); | ||
96 | |||
97 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); | ||
98 | /*virtual*/ F32 getNativeAspectRatio(); | ||
99 | /*virtual*/ F32 getPixelAspectRatio(); | ||
100 | /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } | ||
101 | |||
102 | /*virtual*/ void beforeDialog(); | ||
103 | /*virtual*/ void afterDialog(); | ||
104 | |||
105 | /*virtual*/ BOOL dialog_color_picker(F32 *r, F32 *g, F32 *b); | ||
106 | |||
107 | /*virtual*/ void *getPlatformWindow(); | ||
108 | /*virtual*/ void bringToFront() {}; | ||
109 | |||
110 | protected: | ||
111 | LLWindowMacOSX( | ||
112 | char *title, char *name, int x, int y, int width, int height, U32 flags, | ||
113 | BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, | ||
114 | BOOL ignore_pixel_depth); | ||
115 | ~LLWindowMacOSX(); | ||
116 | |||
117 | void initCursors(); | ||
118 | BOOL isValid(); | ||
119 | void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); | ||
120 | |||
121 | |||
122 | // Changes display resolution. Returns true if successful | ||
123 | BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); | ||
124 | |||
125 | // Go back to last fullscreen display resolution. | ||
126 | BOOL setFullscreenResolution(); | ||
127 | |||
128 | // Restore the display resolution to its value before we ran the app. | ||
129 | BOOL resetDisplayResolution(); | ||
130 | |||
131 | void minimize(); | ||
132 | void restore(); | ||
133 | |||
134 | BOOL shouldPostQuit() { return mPostQuit; } | ||
135 | |||
136 | |||
137 | protected: | ||
138 | // | ||
139 | // Platform specific methods | ||
140 | // | ||
141 | |||
142 | // create or re-create the GL context/window. Called from the constructor and switchContext(). | ||
143 | BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); | ||
144 | void destroyContext(); | ||
145 | void setupFailure(const char* text, const char* caption, U32 type); | ||
146 | static pascal OSStatus staticEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData); | ||
147 | OSStatus eventHandler (EventHandlerCallRef myHandler, EventRef event); | ||
148 | void adjustCursorDecouple(bool warpingMouse = false); | ||
149 | void fixWindowSize(void); | ||
150 | void stopDockTileBounce(); | ||
151 | |||
152 | |||
153 | // | ||
154 | // Platform specific variables | ||
155 | // | ||
156 | WindowRef mWindow; | ||
157 | AGLContext mContext; | ||
158 | AGLPixelFormat mPixelFormat; | ||
159 | CGDirectDisplayID mDisplay; | ||
160 | CFDictionaryRef mOldDisplayMode; | ||
161 | EventLoopTimerRef mTimer; | ||
162 | EventHandlerUPP mEventHandlerUPP; | ||
163 | EventHandlerRef mGlobalHandlerRef; | ||
164 | EventHandlerRef mWindowHandlerRef; | ||
165 | Rect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() | ||
166 | Str255 mWindowTitle; | ||
167 | double mOriginalAspectRatio; | ||
168 | BOOL mSimulatedRightClick; | ||
169 | UInt32 mLastModifiers; | ||
170 | BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. | ||
171 | // Used to allow event processing when putting up dialogs in fullscreen mode. | ||
172 | BOOL mCursorDecoupled; | ||
173 | S32 mCursorLastEventDeltaX; | ||
174 | S32 mCursorLastEventDeltaY; | ||
175 | BOOL mCursorIgnoreNextDelta; | ||
176 | BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. | ||
177 | LLCoordScreen mNeedsResizeSize; | ||
178 | F32 mOverrideAspectRatio; | ||
179 | BOOL mMinimized; | ||
180 | |||
181 | F32 mBounceTime; | ||
182 | NMRec mBounceRec; | ||
183 | LLTimer mBounceTimer; | ||
184 | |||
185 | friend class LLWindowManager; | ||
186 | }; | ||
187 | |||
188 | |||
189 | class LLSplashScreenMacOSX : public LLSplashScreen | ||
190 | { | ||
191 | public: | ||
192 | LLSplashScreenMacOSX(); | ||
193 | virtual ~LLSplashScreenMacOSX(); | ||
194 | |||
195 | /*virtual*/ void showImpl(); | ||
196 | /*virtual*/ void updateImpl(const char* mesg); | ||
197 | /*virtual*/ void hideImpl(); | ||
198 | |||
199 | private: | ||
200 | WindowRef mWindow; | ||
201 | }; | ||
202 | |||
203 | S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type); | ||
204 | |||
205 | void load_url_external(const char* url); | ||
206 | void shell_open( const char* file_path ); | ||
207 | |||
208 | #endif //LL_LLWINDOWMACOSX_H | ||
diff --git a/linden/indra/llwindow/llwindowmesaheadless.cpp b/linden/indra/llwindow/llwindowmesaheadless.cpp new file mode 100644 index 0000000..7e5f4b0 --- /dev/null +++ b/linden/indra/llwindow/llwindowmesaheadless.cpp | |||
@@ -0,0 +1,83 @@ | |||
1 | /** | ||
2 | * @file llwindowmesaheadless.cpp | ||
3 | * @brief Platform-dependent implementation of llwindow | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_MESA_HEADLESS | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | #include "indra_constants.h" | ||
32 | |||
33 | #include "llwindowmesaheadless.h" | ||
34 | #include "llgl.h" | ||
35 | #include "llglheaders.h" | ||
36 | |||
37 | #define MESA_CHANNEL_TYPE GL_UNSIGNED_SHORT | ||
38 | #define MESA_CHANNEL_SIZE 2 | ||
39 | |||
40 | U16 *gMesaBuffer = NULL; | ||
41 | |||
42 | // | ||
43 | // LLWindowMesaHeadless | ||
44 | // | ||
45 | LLWindowMesaHeadless::LLWindowMesaHeadless(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
46 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
47 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) | ||
48 | : LLWindow(fullscreen, flags) | ||
49 | { | ||
50 | if (use_gl) | ||
51 | { | ||
52 | llinfos << "MESA Init" << llendl; | ||
53 | mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL ); | ||
54 | |||
55 | /* Allocate the image buffer */ | ||
56 | mMesaBuffer = new unsigned char [width * height * 4 * MESA_CHANNEL_SIZE]; | ||
57 | llassert(mMesaBuffer); | ||
58 | |||
59 | gMesaBuffer = (U16*)mMesaBuffer; | ||
60 | |||
61 | /* Bind the buffer to the context and make it current */ | ||
62 | if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height )) | ||
63 | { | ||
64 | llerrs << "MESA: OSMesaMakeCurrent failed!" << llendl; | ||
65 | } | ||
66 | |||
67 | llverify(gGLManager.initGL()); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | |||
72 | LLWindowMesaHeadless::~LLWindowMesaHeadless() | ||
73 | { | ||
74 | delete mMesaBuffer; | ||
75 | OSMesaDestroyContext( mMesaContext ); | ||
76 | } | ||
77 | |||
78 | void LLWindowMesaHeadless::swapBuffers() | ||
79 | { | ||
80 | glFinish(); | ||
81 | } | ||
82 | |||
83 | #endif | ||
diff --git a/linden/indra/llwindow/llwindowmesaheadless.h b/linden/indra/llwindow/llwindowmesaheadless.h new file mode 100644 index 0000000..f8599c6 --- /dev/null +++ b/linden/indra/llwindow/llwindowmesaheadless.h | |||
@@ -0,0 +1,123 @@ | |||
1 | /** | ||
2 | * @file llwindowmesaheadless.h | ||
3 | * @brief Windows implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWMESAHEADLESS_H | ||
29 | #define LL_LLWINDOWMESAHEADLESS_H | ||
30 | |||
31 | #if LL_MESA_HEADLESS | ||
32 | |||
33 | #include "llwindow.h" | ||
34 | #include "GL/osmesa.h" | ||
35 | |||
36 | class LLWindowMesaHeadless : public LLWindow | ||
37 | { | ||
38 | public: | ||
39 | /*virtual*/ void show() {}; | ||
40 | /*virtual*/ void hide() {}; | ||
41 | /*virtual*/ void close() {}; | ||
42 | /*virtual*/ BOOL getVisible() {return FALSE;}; | ||
43 | /*virtual*/ BOOL getMinimized() {return FALSE;}; | ||
44 | /*virtual*/ BOOL getMaximized() {return FALSE;}; | ||
45 | /*virtual*/ BOOL maximize() {return FALSE;}; | ||
46 | /*virtual*/ BOOL getFullscreen() {return FALSE;}; | ||
47 | /*virtual*/ BOOL getPosition(LLCoordScreen *position) {return FALSE;}; | ||
48 | /*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;}; | ||
49 | /*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;}; | ||
50 | /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; | ||
51 | /*virtual*/ BOOL setSize(LLCoordScreen size) {return FALSE;}; | ||
52 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) {return FALSE;}; | ||
53 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; | ||
54 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; | ||
55 | /*virtual*/ void showCursor() {}; | ||
56 | /*virtual*/ void hideCursor() {}; | ||
57 | /*virtual*/ void showCursorFromMouseMove() {}; | ||
58 | /*virtual*/ void hideCursorUntilMouseMove() {}; | ||
59 | /*virtual*/ BOOL isCursorHidden() {return FALSE;}; | ||
60 | /*virtual*/ void setCursor(ECursorType cursor) {}; | ||
61 | //virtual ECursorType getCursor() { return mCurrentCursor; }; | ||
62 | /*virtual*/ void captureMouse() {}; | ||
63 | /*virtual*/ void releaseMouse() {}; | ||
64 | /*virtual*/ void setMouseClipping( BOOL b ) {}; | ||
65 | /*virtual*/ BOOL isClipboardTextAvailable() {return FALSE; }; | ||
66 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) {return FALSE; }; | ||
67 | /*virtual*/ BOOL copyTextToClipboard(const LLWString &src) {return FALSE; }; | ||
68 | /*virtual*/ void flashIcon(F32 seconds) {}; | ||
69 | /*virtual*/ F32 getGamma() {return 1.0f; }; | ||
70 | /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma | ||
71 | /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) | ||
72 | //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
73 | /*virtual*/ void gatherInput() {}; | ||
74 | /*virtual*/ void delayInputProcessing() {}; | ||
75 | /*virtual*/ void swapBuffers(); | ||
76 | |||
77 | /*virtual*/ LLString getTempFileName() {return LLString(""); }; | ||
78 | /*virtual*/ void deleteFile( const char* file_name ) {}; | ||
79 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ) {return 0; }; | ||
80 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL) { return FALSE; }; | ||
81 | |||
82 | |||
83 | // handy coordinate space conversion routines | ||
84 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) { return FALSE; }; | ||
85 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) { return FALSE; }; | ||
86 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) { return FALSE; }; | ||
87 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) { return FALSE; }; | ||
88 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) { return FALSE; }; | ||
89 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) { return FALSE; }; | ||
90 | |||
91 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; | ||
92 | /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; | ||
93 | /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; | ||
94 | /*virtual*/ void setNativeAspectRatio(F32 ratio) {} | ||
95 | |||
96 | /*virtual*/ void *getPlatformWindow() { return 0; }; | ||
97 | /*virtual*/ void bringToFront() {}; | ||
98 | |||
99 | LLWindowMesaHeadless(char *title, char *name, S32 x, S32 y, S32 width, S32 height, | ||
100 | U32 flags, BOOL fullscreen, BOOL clearBg, | ||
101 | BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); | ||
102 | ~LLWindowMesaHeadless(); | ||
103 | |||
104 | private: | ||
105 | OSMesaContext mMesaContext; | ||
106 | unsigned char * mMesaBuffer; | ||
107 | }; | ||
108 | |||
109 | class LLSplashScreenMesaHeadless : public LLSplashScreen | ||
110 | { | ||
111 | public: | ||
112 | LLSplashScreenMesaHeadless() {}; | ||
113 | virtual ~LLSplashScreenMesaHeadless() {}; | ||
114 | |||
115 | /*virtual*/ void showImpl() {}; | ||
116 | /*virtual*/ void updateImpl(const char* mesg) {}; | ||
117 | /*virtual*/ void hideImpl() {}; | ||
118 | |||
119 | }; | ||
120 | |||
121 | #endif | ||
122 | |||
123 | #endif //LL_LLWINDOWMESAHEADLESS_H | ||
diff --git a/linden/indra/llwindow/llwindowsdl.cpp b/linden/indra/llwindow/llwindowsdl.cpp new file mode 100644 index 0000000..a94284e --- /dev/null +++ b/linden/indra/llwindow/llwindowsdl.cpp | |||
@@ -0,0 +1,2506 @@ | |||
1 | /** | ||
2 | * @file llwindowsdl.cpp | ||
3 | * @brief Platform-dependent implementation of llwindow | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #if LL_SDL | ||
29 | |||
30 | #include "linden_common.h" | ||
31 | |||
32 | #include "llwindowsdl.h" | ||
33 | #include "llkeyboardsdl.h" | ||
34 | #include "llerror.h" | ||
35 | #include "llgl.h" | ||
36 | #include "llstring.h" | ||
37 | #include "lldir.h" | ||
38 | |||
39 | #include "llglheaders.h" | ||
40 | |||
41 | #include "indra_constants.h" | ||
42 | |||
43 | #if LL_GTK | ||
44 | # include "gtk/gtk.h" | ||
45 | #endif // LL_GTK | ||
46 | |||
47 | #if LL_LINUX | ||
48 | // not necessarily available on random SDL platforms, so #if LL_LINUX | ||
49 | // for execv(), waitpid(), fork() | ||
50 | # include <unistd.h> | ||
51 | # include <sys/types.h> | ||
52 | # include <sys/wait.h> | ||
53 | #endif // LL_LINUX | ||
54 | |||
55 | extern BOOL gDebugWindowProc; | ||
56 | |||
57 | // culled from winuser.h | ||
58 | //const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ | ||
59 | // On the Mac, the scroll wheel reports a delta of 1 for each detent. | ||
60 | // There's also acceleration for faster scrolling, based on a slider in the system preferences. | ||
61 | const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */ | ||
62 | const S32 BITS_PER_PIXEL = 32; | ||
63 | const S32 MAX_NUM_RESOLUTIONS = 32; | ||
64 | |||
65 | // | ||
66 | // LLWindowSDL | ||
67 | // | ||
68 | |||
69 | #if LL_X11 | ||
70 | # include <X11/Xutil.h> | ||
71 | // A global! Well, SDL isn't really designed for communicating | ||
72 | // with multiple physical X11 displays. Heck, it's not really | ||
73 | // designed for multiple X11 windows. | ||
74 | // So, we need this for the SDL/X11 event filter callback (which | ||
75 | // doesnt have a userdata parameter) and more. | ||
76 | static Display *SDL_Display = NULL; | ||
77 | static Window SDL_XWindowID = None; | ||
78 | #endif //LL_X11 | ||
79 | |||
80 | // TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for the same reasons) | ||
81 | // For SDL, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. | ||
82 | // The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these | ||
83 | // require a pointer to the LLWindowMacSDL object. Stash it here and maintain in the constructor and destructor. | ||
84 | // This assumes that there will be only one object of this class at any time. Hopefully this is true. | ||
85 | static LLWindowSDL *gWindowImplementation = NULL; | ||
86 | |||
87 | static BOOL was_fullscreen = FALSE; | ||
88 | |||
89 | // Cross-platform bits: | ||
90 | |||
91 | void show_window_creation_error(const char* title) | ||
92 | { | ||
93 | llwarns << title << llendl; | ||
94 | shell_open( "help/window_creation_error.html"); | ||
95 | /* | ||
96 | OSMessageBox( | ||
97 | "Second Life is unable to run because it can't set up your display.\n" | ||
98 | "We need to be able to make a 32-bit color window at 1024x768, with\n" | ||
99 | "an 8 bit alpha channel.\n" | ||
100 | "\n" | ||
101 | "First, be sure your monitor is set to True Color (32-bit) in\n" | ||
102 | "Start -> Control Panels -> Display -> Settings.\n" | ||
103 | "\n" | ||
104 | "Otherwise, this may be due to video card driver issues.\n" | ||
105 | "Please make sure you have the latest video card drivers installed.\n" | ||
106 | "ATI drivers are available at http://www.ati.com/\n" | ||
107 | "nVidia drivers are available at http://www.nvidia.com/\n" | ||
108 | "\n" | ||
109 | "If you continue to receive this message, contact customer service.", | ||
110 | title, | ||
111 | OSMB_OK); | ||
112 | */ | ||
113 | } | ||
114 | |||
115 | |||
116 | #if LL_GTK | ||
117 | // Check the runtime GTK version for goodness. | ||
118 | static BOOL maybe_do_gtk_diagnostics(void) | ||
119 | { | ||
120 | static BOOL done_gtk_diag = FALSE; | ||
121 | static BOOL is_good = TRUE; | ||
122 | gtk_disable_setlocale(); | ||
123 | if ((!done_gtk_diag) && gtk_init_check(NULL, NULL)) | ||
124 | { | ||
125 | llinfos << "GTK Initialized." << llendl; | ||
126 | llinfos << "- Compiled against GTK version " | ||
127 | << GTK_MAJOR_VERSION << "." | ||
128 | << GTK_MINOR_VERSION << "." | ||
129 | << GTK_MICRO_VERSION << llendl; | ||
130 | llinfos << "- Running against GTK version " | ||
131 | << gtk_major_version << "." | ||
132 | << gtk_minor_version << "." | ||
133 | << gtk_micro_version << llendl; | ||
134 | gchar *gtk_warning; | ||
135 | gtk_warning = gtk_check_version(GTK_MAJOR_VERSION, | ||
136 | GTK_MINOR_VERSION, | ||
137 | GTK_MICRO_VERSION); | ||
138 | if (gtk_warning) | ||
139 | { | ||
140 | llwarns << "- GTK COMPATIBILITY WARNING: " << | ||
141 | gtk_warning << llendl; | ||
142 | is_good = FALSE; | ||
143 | } | ||
144 | |||
145 | done_gtk_diag = TRUE; | ||
146 | } | ||
147 | return is_good; | ||
148 | } | ||
149 | #endif // LL_GTK | ||
150 | |||
151 | |||
152 | BOOL check_for_card(const char* RENDERER, const char* bad_card) | ||
153 | { | ||
154 | if (!strncasecmp(RENDERER, bad_card, strlen(bad_card))) | ||
155 | { | ||
156 | char buffer[1024]; | ||
157 | sprintf(buffer, | ||
158 | "Your video card appears to be a %s, which Second Life does not support.\n" | ||
159 | "\n" | ||
160 | "Second Life requires a video card with 32 Mb of memory or more, as well as\n" | ||
161 | "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" | ||
162 | "and ATI Radeon 8500 or better.\n" | ||
163 | "\n" | ||
164 | "If you own a supported card and continue to receive this message, try \n" | ||
165 | "updating to the latest video card drivers. Otherwise look in the\n" | ||
166 | "secondlife.com support section or e-mail technical support\n" | ||
167 | "\n" | ||
168 | "You can try to run Second Life, but it will probably crash or run\n" | ||
169 | "very slowly. Try anyway?", | ||
170 | bad_card); | ||
171 | S32 button = OSMessageBox(buffer, "Unsupported video card", OSMB_YESNO); | ||
172 | if (OSBTN_YES == button) | ||
173 | { | ||
174 | return FALSE; | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | return TRUE; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | return FALSE; | ||
183 | } | ||
184 | |||
185 | |||
186 | |||
187 | |||
188 | LLWindowSDL::LLWindowSDL(char *title, S32 x, S32 y, S32 width, | ||
189 | S32 height, U32 flags, | ||
190 | BOOL fullscreen, BOOL clearBg, | ||
191 | BOOL disable_vsync, BOOL use_gl, | ||
192 | BOOL ignore_pixel_depth) | ||
193 | : LLWindow(fullscreen, flags), mGamma(1.0f) | ||
194 | { | ||
195 | // Initialize the keyboard | ||
196 | gKeyboard = new LLKeyboardSDL(); | ||
197 | // Note that we can't set up key-repeat until after SDL has init'd video | ||
198 | |||
199 | // Ignore use_gl for now, only used for drones on PC | ||
200 | mWindow = NULL; | ||
201 | mCursorDecoupled = FALSE; | ||
202 | mCursorLastEventDeltaX = 0; | ||
203 | mCursorLastEventDeltaY = 0; | ||
204 | mCursorIgnoreNextDelta = FALSE; | ||
205 | mNeedsResize = FALSE; | ||
206 | mOverrideAspectRatio = 0.f; | ||
207 | mGrabbyKeyFlags = 0; | ||
208 | mReallyCapturedCount = 0; | ||
209 | mHaveInputFocus = -1; | ||
210 | mIsMinimized = -1; | ||
211 | |||
212 | // Get the original aspect ratio of the main device. | ||
213 | mOriginalAspectRatio = 1024.0 / 768.0; // !!! FIXME //(double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); | ||
214 | |||
215 | if (!title) | ||
216 | title = "SDL Window"; // *FIX: (???) | ||
217 | |||
218 | // Stash the window title | ||
219 | mWindowTitle = new char[strlen(title) + 1]; | ||
220 | strcpy(mWindowTitle, title); | ||
221 | |||
222 | // Create the GL context and set it up for windowed or fullscreen, as appropriate. | ||
223 | if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) | ||
224 | { | ||
225 | gGLManager.initGL(); | ||
226 | |||
227 | //start with arrow cursor | ||
228 | initCursors(); | ||
229 | setCursor( UI_CURSOR_ARROW ); | ||
230 | } | ||
231 | |||
232 | stop_glerror(); | ||
233 | |||
234 | // Stash an object pointer for OSMessageBox() | ||
235 | gWindowImplementation = this; | ||
236 | |||
237 | #if LL_X11 | ||
238 | mFlashing = FALSE; | ||
239 | #endif // LL_X11 | ||
240 | } | ||
241 | |||
242 | static SDL_Surface *Load_BMP_Resource(const char *basename) | ||
243 | { | ||
244 | const int PATH_BUFFER_SIZE=1000; | ||
245 | char path_buffer[PATH_BUFFER_SIZE]; | ||
246 | |||
247 | // Figure out where our BMP is living on the disk | ||
248 | snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", | ||
249 | gDirUtilp->getAppRODataDir().c_str(), | ||
250 | gDirUtilp->getDirDelimiter().c_str(), | ||
251 | gDirUtilp->getDirDelimiter().c_str(), | ||
252 | basename); | ||
253 | path_buffer[PATH_BUFFER_SIZE-1] = '\0'; | ||
254 | |||
255 | return SDL_LoadBMP(path_buffer); | ||
256 | } | ||
257 | |||
258 | BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) | ||
259 | { | ||
260 | //bool glneedsinit = false; | ||
261 | // const char *gllibname = null; | ||
262 | |||
263 | llinfos << "createContext, fullscreen=" << fullscreen << | ||
264 | " size=" << width << "x" << height << llendl; | ||
265 | |||
266 | // captures don't survive contexts | ||
267 | mGrabbyKeyFlags = 0; | ||
268 | mReallyCapturedCount = 0; | ||
269 | |||
270 | if (SDL_Init(SDL_INIT_VIDEO) < 0) | ||
271 | { | ||
272 | llinfos << "sdl_init() failed! " << SDL_GetError() << llendl; | ||
273 | setupFailure("window creation error", "error", OSMB_OK); | ||
274 | return false; | ||
275 | } | ||
276 | |||
277 | SDL_version c_sdl_version; | ||
278 | SDL_VERSION(&c_sdl_version); | ||
279 | llinfos << "Compiled against SDL " | ||
280 | << int(c_sdl_version.major) << "." | ||
281 | << int(c_sdl_version.minor) << "." | ||
282 | << int(c_sdl_version.patch) << llendl; | ||
283 | const SDL_version *r_sdl_version; | ||
284 | r_sdl_version = SDL_Linked_Version(); | ||
285 | llinfos << " Running against SDL " | ||
286 | << int(r_sdl_version->major) << "." | ||
287 | << int(r_sdl_version->minor) << "." | ||
288 | << int(r_sdl_version->patch) << llendl; | ||
289 | |||
290 | const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo( ); | ||
291 | if (!videoInfo) | ||
292 | { | ||
293 | llinfos << "SDL_GetVideoInfo() failed! " << SDL_GetError() << llendl; | ||
294 | setupFailure("Window creation error", "Error", OSMB_OK); | ||
295 | return FALSE; | ||
296 | } | ||
297 | |||
298 | SDL_EnableUNICODE(1); | ||
299 | SDL_WM_SetCaption(mWindowTitle, mWindowTitle); | ||
300 | |||
301 | // Set the application icon. | ||
302 | SDL_Surface *bmpsurface; | ||
303 | bmpsurface = Load_BMP_Resource("ll_icon.BMP"); | ||
304 | if (bmpsurface) | ||
305 | { | ||
306 | // This attempts to give a black-keyed mask to the icon. | ||
307 | SDL_SetColorKey(bmpsurface, | ||
308 | SDL_SRCCOLORKEY, | ||
309 | SDL_MapRGB(bmpsurface->format, 0,0,0) ); | ||
310 | SDL_WM_SetIcon(bmpsurface, NULL); | ||
311 | // The SDL examples cheerfully avoid freeing the icon | ||
312 | // surface, but I'm betting that's leaky. | ||
313 | SDL_FreeSurface(bmpsurface); | ||
314 | bmpsurface = NULL; | ||
315 | } | ||
316 | |||
317 | // note: these SetAttributes make Tom's 9600-on-AMD64 fail to | ||
318 | // get a visual, but it's broken anyway when it does, and without | ||
319 | // these SetAttributes we might easily get an avoidable substandard | ||
320 | // visual to work with on most other machines. | ||
321 | SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); | ||
322 | SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); | ||
323 | SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); | ||
324 | SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); | ||
325 | SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); | ||
326 | |||
327 | // *FIX: try to toggle vsync here? | ||
328 | |||
329 | mFullscreen = fullscreen; | ||
330 | was_fullscreen = fullscreen; | ||
331 | |||
332 | int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; | ||
333 | |||
334 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | ||
335 | |||
336 | mSDLFlags = sdlflags; | ||
337 | |||
338 | if (mFullscreen) | ||
339 | { | ||
340 | llinfos << "createContext: setting up fullscreen " << width << "x" << height << llendl; | ||
341 | |||
342 | // If the requested width or height is 0, find the best default for the monitor. | ||
343 | if((width == 0) || (height == 0)) | ||
344 | { | ||
345 | // Scan through the list of modes, looking for one which has: | ||
346 | // height between 700 and 800 | ||
347 | // aspect ratio closest to the user's original mode | ||
348 | S32 resolutionCount = 0; | ||
349 | LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); | ||
350 | |||
351 | if(resolutionList != NULL) | ||
352 | { | ||
353 | F32 closestAspect = 0; | ||
354 | U32 closestHeight = 0; | ||
355 | U32 closestWidth = 0; | ||
356 | int i; | ||
357 | |||
358 | llinfos << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << llendl; | ||
359 | |||
360 | for(i=0; i < resolutionCount; i++) | ||
361 | { | ||
362 | F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; | ||
363 | |||
364 | llinfos << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << llendl; | ||
365 | |||
366 | if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) && | ||
367 | (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio))) | ||
368 | { | ||
369 | llinfos << " (new closest mode) " << llendl; | ||
370 | |||
371 | // This is the closest mode we've seen yet. | ||
372 | closestWidth = resolutionList[i].mWidth; | ||
373 | closestHeight = resolutionList[i].mHeight; | ||
374 | closestAspect = aspect; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | width = closestWidth; | ||
379 | height = closestHeight; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | if((width == 0) || (height == 0)) | ||
384 | { | ||
385 | // Mode search failed for some reason. Use the old-school default. | ||
386 | width = 1024; | ||
387 | height = 768; | ||
388 | } | ||
389 | |||
390 | mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); | ||
391 | |||
392 | if (mWindow) | ||
393 | { | ||
394 | mFullscreen = TRUE; | ||
395 | was_fullscreen = TRUE; | ||
396 | mFullscreenWidth = mWindow->w; | ||
397 | mFullscreenHeight = mWindow->h; | ||
398 | mFullscreenBits = mWindow->format->BitsPerPixel; | ||
399 | mFullscreenRefresh = -1; | ||
400 | |||
401 | llinfos << "Running at " << mFullscreenWidth | ||
402 | << "x" << mFullscreenHeight | ||
403 | << "x" << mFullscreenBits | ||
404 | << " @ " << mFullscreenRefresh | ||
405 | << llendl; | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | llwarns << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << llendl; | ||
410 | // No fullscreen support | ||
411 | mFullscreen = FALSE; | ||
412 | was_fullscreen = FALSE; | ||
413 | mFullscreenWidth = -1; | ||
414 | mFullscreenHeight = -1; | ||
415 | mFullscreenBits = -1; | ||
416 | mFullscreenRefresh = -1; | ||
417 | |||
418 | char error[256]; | ||
419 | sprintf(error, "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); | ||
420 | OSMessageBox(error, "Error", OSMB_OK); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | if(!mFullscreen && (mWindow == NULL)) | ||
425 | { | ||
426 | if (width == 0) | ||
427 | width = 1024; | ||
428 | if (height == 0) | ||
429 | width = 768; | ||
430 | |||
431 | llinfos << "createContext: creating window " << width << "x" << height << "x" << bits << llendl; | ||
432 | mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); | ||
433 | |||
434 | if (!mWindow) | ||
435 | { | ||
436 | llwarns << "createContext: window creation failure. SDL: " << SDL_GetError() << llendl; | ||
437 | setupFailure("Window creation error", "Error", OSMB_OK); | ||
438 | return FALSE; | ||
439 | } | ||
440 | } else if (!mFullscreen && (mWindow != NULL)) | ||
441 | { | ||
442 | llinfos << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << llendl; | ||
443 | } | ||
444 | |||
445 | /*if (!load_all_glsyms(gllibname)) | ||
446 | { | ||
447 | SDL_QuitSubSystem(SDL_INIT_VIDEO); | ||
448 | return FALSE; | ||
449 | }*/ | ||
450 | |||
451 | gGLManager.mVRAM = videoInfo->video_mem / 1024; | ||
452 | if (gGLManager.mVRAM != 0) | ||
453 | { | ||
454 | llinfos << "Detected " << gGLManager.mVRAM << "MB VRAM." << llendl; | ||
455 | } | ||
456 | // If VRAM is not detected, that is handled later | ||
457 | |||
458 | #if 0 // *FIX: all video cards suck under Linux. :) | ||
459 | // Since we just created the context, it needs to be set up. | ||
460 | glNeedsInit = TRUE; | ||
461 | if(glNeedsInit) | ||
462 | { | ||
463 | // Check for some explicitly unsupported cards. | ||
464 | const char* RENDERER = (const char*) glGetString(GL_RENDERER); | ||
465 | |||
466 | const char* CARD_LIST[] = | ||
467 | { "RAGE 128", | ||
468 | "RIVA TNT2", | ||
469 | "Intel 810", | ||
470 | "3Dfx/Voodoo3", | ||
471 | "Radeon 7000", | ||
472 | "Radeon 7200", | ||
473 | "Radeon 7500", | ||
474 | "Radeon DDR", | ||
475 | "Radeon VE", | ||
476 | "GDI Generic" }; | ||
477 | const S32 CARD_COUNT = sizeof(CARD_LIST)/sizeof(char*); | ||
478 | |||
479 | // Future candidates: | ||
480 | // ProSavage/Twister | ||
481 | // SuperSavage | ||
482 | |||
483 | S32 i; | ||
484 | for (i = 0; i < CARD_COUNT; i++) | ||
485 | { | ||
486 | if (check_for_card(RENDERER, CARD_LIST[i])) | ||
487 | { | ||
488 | close(); | ||
489 | shell_open( "help/unsupported_card.html" ); | ||
490 | return FALSE; | ||
491 | } | ||
492 | } | ||
493 | } | ||
494 | #endif | ||
495 | |||
496 | GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; | ||
497 | |||
498 | glGetIntegerv(GL_RED_BITS, &redBits); | ||
499 | glGetIntegerv(GL_GREEN_BITS, &greenBits); | ||
500 | glGetIntegerv(GL_BLUE_BITS, &blueBits); | ||
501 | glGetIntegerv(GL_ALPHA_BITS, &alphaBits); | ||
502 | glGetIntegerv(GL_DEPTH_BITS, &depthBits); | ||
503 | glGetIntegerv(GL_STENCIL_BITS, &stencilBits); | ||
504 | |||
505 | llinfos << "GL buffer:" << llendl | ||
506 | llinfos << " Red Bits " << S32(redBits) << llendl | ||
507 | llinfos << " Green Bits " << S32(greenBits) << llendl | ||
508 | llinfos << " Blue Bits " << S32(blueBits) << llendl | ||
509 | llinfos << " Alpha Bits " << S32(alphaBits) << llendl | ||
510 | llinfos << " Depth Bits " << S32(depthBits) << llendl | ||
511 | llinfos << " Stencil Bits " << S32(stencilBits) << llendl; | ||
512 | |||
513 | GLint colorBits = redBits + greenBits + blueBits + alphaBits; | ||
514 | // fixme: actually, it's REALLY important for picking that we get at | ||
515 | // least 8 bits each of red,green,blue. Alpha we can be a bit more | ||
516 | // relaxed about if we have to. | ||
517 | if (colorBits < 32) | ||
518 | { | ||
519 | close(); | ||
520 | setupFailure( | ||
521 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
522 | "Please go to Control Panels -> Display -> Settings and\n" | ||
523 | "set the screen to 32-bit color.\n" | ||
524 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
525 | "will automatically adjust the screen each time it runs.", | ||
526 | "Error", | ||
527 | OSMB_OK); | ||
528 | return FALSE; | ||
529 | } | ||
530 | |||
531 | #if 0 // *FIX: we're going to brave it for now... | ||
532 | if (alphaBits < 8) | ||
533 | { | ||
534 | close(); | ||
535 | setupFailure( | ||
536 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
537 | "channel. Usually this is due to video card driver issues.\n" | ||
538 | "Please make sure you have the latest video card drivers installed.\n" | ||
539 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
540 | "Control Panels -> Display -> Settings.\n" | ||
541 | "If you continue to receive this message, contact customer service.", | ||
542 | "Error", | ||
543 | OSMB_OK); | ||
544 | return FALSE; | ||
545 | } | ||
546 | #endif | ||
547 | |||
548 | #if LL_X11 | ||
549 | init_x11clipboard(); | ||
550 | #endif // LL_X11 | ||
551 | |||
552 | // We need to do this here, once video is init'd | ||
553 | if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, | ||
554 | SDL_DEFAULT_REPEAT_INTERVAL)) | ||
555 | llwarns << "Couldn't enable key-repeat: " << SDL_GetError() <<llendl; | ||
556 | |||
557 | // Don't need to get the current gamma, since there's a call that restores it to the system defaults. | ||
558 | return TRUE; | ||
559 | } | ||
560 | |||
561 | |||
562 | // changing fullscreen resolution, or switching between windowed and fullscreen mode. | ||
563 | BOOL LLWindowSDL::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) | ||
564 | { | ||
565 | const BOOL needsRebuild = TRUE; // Just nuke the context and start over. | ||
566 | BOOL result = true; | ||
567 | |||
568 | llinfos << "switchContext, fullscreen=" << fullscreen << llendl; | ||
569 | stop_glerror(); | ||
570 | if(needsRebuild) | ||
571 | { | ||
572 | destroyContext(); | ||
573 | result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); | ||
574 | if (result) | ||
575 | { | ||
576 | gGLManager.initGL(); | ||
577 | |||
578 | //start with arrow cursor | ||
579 | initCursors(); | ||
580 | setCursor( UI_CURSOR_ARROW ); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | stop_glerror(); | ||
585 | |||
586 | return result; | ||
587 | } | ||
588 | |||
589 | void LLWindowSDL::destroyContext() | ||
590 | { | ||
591 | llinfos << "destroyContext begins" << llendl; | ||
592 | #if LL_X11 | ||
593 | quit_x11clipboard(); | ||
594 | #endif // LL_X11 | ||
595 | |||
596 | // Clean up remaining GL state before blowing away window | ||
597 | llinfos << "shutdownGL begins" << llendl; | ||
598 | gGLManager.shutdownGL(); | ||
599 | llinfos << "SDL_QuitSS/VID begins" << llendl; | ||
600 | SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... | ||
601 | //unload_all_glsyms(); | ||
602 | |||
603 | mWindow = NULL; | ||
604 | } | ||
605 | |||
606 | LLWindowSDL::~LLWindowSDL() | ||
607 | { | ||
608 | quitCursors(); | ||
609 | destroyContext(); | ||
610 | |||
611 | if(mSupportedResolutions != NULL) | ||
612 | { | ||
613 | delete []mSupportedResolutions; | ||
614 | } | ||
615 | |||
616 | delete[] mWindowTitle; | ||
617 | |||
618 | gWindowImplementation = NULL; | ||
619 | } | ||
620 | |||
621 | |||
622 | void LLWindowSDL::show() | ||
623 | { | ||
624 | // *FIX: What to do with SDL? | ||
625 | } | ||
626 | |||
627 | void LLWindowSDL::hide() | ||
628 | { | ||
629 | // *FIX: What to do with SDL? | ||
630 | } | ||
631 | |||
632 | void LLWindowSDL::minimize() | ||
633 | { | ||
634 | // *FIX: What to do with SDL? | ||
635 | } | ||
636 | |||
637 | void LLWindowSDL::restore() | ||
638 | { | ||
639 | // *FIX: What to do with SDL? | ||
640 | } | ||
641 | |||
642 | |||
643 | // close() destroys all OS-specific code associated with a window. | ||
644 | // Usually called from LLWindowManager::destroyWindow() | ||
645 | void LLWindowSDL::close() | ||
646 | { | ||
647 | // Is window is already closed? | ||
648 | // if (!mWindow) | ||
649 | // { | ||
650 | // return; | ||
651 | // } | ||
652 | |||
653 | // Make sure cursor is visible and we haven't mangled the clipping state. | ||
654 | setMouseClipping(FALSE); | ||
655 | showCursor(); | ||
656 | |||
657 | destroyContext(); | ||
658 | } | ||
659 | |||
660 | BOOL LLWindowSDL::isValid() | ||
661 | { | ||
662 | return (mWindow != NULL); | ||
663 | } | ||
664 | |||
665 | BOOL LLWindowSDL::getVisible() | ||
666 | { | ||
667 | BOOL result = FALSE; | ||
668 | |||
669 | // *FIX: This isn't really right... | ||
670 | // Then what is? | ||
671 | if (mWindow) | ||
672 | { | ||
673 | result = TRUE; | ||
674 | } | ||
675 | |||
676 | return(result); | ||
677 | } | ||
678 | |||
679 | BOOL LLWindowSDL::getMinimized() | ||
680 | { | ||
681 | BOOL result = FALSE; | ||
682 | |||
683 | if (mWindow && (1 == mIsMinimized)) | ||
684 | { | ||
685 | result = TRUE; | ||
686 | } | ||
687 | return(result); | ||
688 | } | ||
689 | |||
690 | BOOL LLWindowSDL::getMaximized() | ||
691 | { | ||
692 | BOOL result = FALSE; | ||
693 | |||
694 | if (mWindow) | ||
695 | { | ||
696 | // TODO | ||
697 | } | ||
698 | |||
699 | return(result); | ||
700 | } | ||
701 | |||
702 | BOOL LLWindowSDL::maximize() | ||
703 | { | ||
704 | // TODO | ||
705 | return FALSE; | ||
706 | } | ||
707 | |||
708 | BOOL LLWindowSDL::getFullscreen() | ||
709 | { | ||
710 | return mFullscreen; | ||
711 | } | ||
712 | |||
713 | BOOL LLWindowSDL::getPosition(LLCoordScreen *position) | ||
714 | { | ||
715 | // *FIX: can anything be done with this? | ||
716 | position->mX = 0; | ||
717 | position->mY = 0; | ||
718 | return TRUE; | ||
719 | } | ||
720 | |||
721 | BOOL LLWindowSDL::getSize(LLCoordScreen *size) | ||
722 | { | ||
723 | if (mWindow) | ||
724 | { | ||
725 | size->mX = mWindow->w; | ||
726 | size->mY = mWindow->h; | ||
727 | return (TRUE); | ||
728 | } | ||
729 | |||
730 | llerrs << "LLWindowSDL::getPosition(): no window and not fullscreen!" << llendl; | ||
731 | return (FALSE); | ||
732 | } | ||
733 | |||
734 | BOOL LLWindowSDL::getSize(LLCoordWindow *size) | ||
735 | { | ||
736 | if (mWindow) | ||
737 | { | ||
738 | size->mX = mWindow->w; | ||
739 | size->mY = mWindow->h; | ||
740 | return (TRUE); | ||
741 | } | ||
742 | |||
743 | llerrs << "LLWindowSDL::getPosition(): no window and not fullscreen!" << llendl; | ||
744 | return (FALSE); | ||
745 | } | ||
746 | |||
747 | BOOL LLWindowSDL::setPosition(const LLCoordScreen position) | ||
748 | { | ||
749 | if(mWindow) | ||
750 | { | ||
751 | // *FIX: (???) | ||
752 | //MacMoveWindow(mWindow, position.mX, position.mY, false); | ||
753 | } | ||
754 | |||
755 | return TRUE; | ||
756 | } | ||
757 | |||
758 | BOOL LLWindowSDL::setSize(const LLCoordScreen size) | ||
759 | { | ||
760 | if(mWindow) | ||
761 | { | ||
762 | // *FIX: (???) | ||
763 | //SizeWindow(mWindow, size.mX, size.mY, true); | ||
764 | } | ||
765 | |||
766 | return TRUE; | ||
767 | } | ||
768 | |||
769 | void LLWindowSDL::swapBuffers() | ||
770 | { | ||
771 | if (mWindow) | ||
772 | SDL_GL_SwapBuffers(); | ||
773 | } | ||
774 | |||
775 | F32 LLWindowSDL::getGamma() | ||
776 | { | ||
777 | return 1/mGamma; | ||
778 | } | ||
779 | |||
780 | BOOL LLWindowSDL::restoreGamma() | ||
781 | { | ||
782 | //CGDisplayRestoreColorSyncSettings(); | ||
783 | SDL_SetGamma(1.0f, 1.0f, 1.0f); | ||
784 | return true; | ||
785 | } | ||
786 | |||
787 | BOOL LLWindowSDL::setGamma(const F32 gamma) | ||
788 | { | ||
789 | mGamma = gamma; | ||
790 | if (mGamma == 0) mGamma = 0.1f; | ||
791 | mGamma = 1/mGamma; | ||
792 | SDL_SetGamma(mGamma, mGamma, mGamma); | ||
793 | return true; | ||
794 | } | ||
795 | |||
796 | BOOL LLWindowSDL::isCursorHidden() | ||
797 | { | ||
798 | return mCursorHidden; | ||
799 | } | ||
800 | |||
801 | |||
802 | |||
803 | // Constrains the mouse to the window. | ||
804 | void LLWindowSDL::setMouseClipping( BOOL b ) | ||
805 | { | ||
806 | //llinfos << "LLWindowSDL::setMouseClipping " << b << llendl; | ||
807 | // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. | ||
808 | mIsMouseClipping = b; | ||
809 | //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); | ||
810 | adjustCursorDecouple(); | ||
811 | } | ||
812 | |||
813 | BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position) | ||
814 | { | ||
815 | BOOL result = TRUE; | ||
816 | LLCoordScreen screen_pos; | ||
817 | |||
818 | if (!convertCoords(position, &screen_pos)) | ||
819 | { | ||
820 | return FALSE; | ||
821 | } | ||
822 | |||
823 | //llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl; | ||
824 | |||
825 | SDL_WarpMouse(screen_pos.mX, screen_pos.mY); | ||
826 | |||
827 | // Under certain circumstances, this will trigger us to decouple the cursor. | ||
828 | adjustCursorDecouple(true); | ||
829 | |||
830 | return result; | ||
831 | } | ||
832 | |||
833 | BOOL LLWindowSDL::getCursorPosition(LLCoordWindow *position) | ||
834 | { | ||
835 | //Point cursor_point; | ||
836 | LLCoordScreen screen_pos; | ||
837 | |||
838 | //GetMouse(&cursor_point); | ||
839 | int x, y; | ||
840 | SDL_GetMouseState(&x, &y); | ||
841 | |||
842 | screen_pos.mX = x; | ||
843 | screen_pos.mY = y; | ||
844 | |||
845 | return convertCoords(screen_pos, position); | ||
846 | } | ||
847 | |||
848 | void LLWindowSDL::adjustCursorDecouple(bool warpingMouse) | ||
849 | { | ||
850 | if(mIsMouseClipping && mCursorHidden) | ||
851 | { | ||
852 | if(warpingMouse) | ||
853 | { | ||
854 | // The cursor should be decoupled. Make sure it is. | ||
855 | if(!mCursorDecoupled) | ||
856 | { | ||
857 | // llinfos << "adjustCursorDecouple: decoupling cursor" << llendl; | ||
858 | //CGAssociateMouseAndMouseCursorPosition(false); | ||
859 | mCursorDecoupled = true; | ||
860 | mCursorIgnoreNextDelta = TRUE; | ||
861 | } | ||
862 | } | ||
863 | } | ||
864 | else | ||
865 | { | ||
866 | // The cursor should not be decoupled. Make sure it isn't. | ||
867 | if(mCursorDecoupled) | ||
868 | { | ||
869 | // llinfos << "adjustCursorDecouple: recoupling cursor" << llendl; | ||
870 | //CGAssociateMouseAndMouseCursorPosition(true); | ||
871 | mCursorDecoupled = false; | ||
872 | } | ||
873 | } | ||
874 | } | ||
875 | |||
876 | F32 LLWindowSDL::getNativeAspectRatio() | ||
877 | { | ||
878 | #if 0 | ||
879 | // RN: this hack presumes that the largest supported resolution is monitor-limited | ||
880 | // and that pixels in that mode are square, therefore defining the native aspect ratio | ||
881 | // of the monitor...this seems to work to a close approximation for most CRTs/LCDs | ||
882 | S32 num_resolutions; | ||
883 | LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); | ||
884 | |||
885 | |||
886 | return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); | ||
887 | //rn: AC | ||
888 | #endif | ||
889 | |||
890 | // MBW -- there are a couple of bad assumptions here. One is that the display list won't include | ||
891 | // ridiculous resolutions nobody would ever use. The other is that the list is in order. | ||
892 | |||
893 | // New assumptions: | ||
894 | // - pixels are square (the only reasonable choice, really) | ||
895 | // - The user runs their display at a native resolution, so the resolution of the display | ||
896 | // when the app is launched has an aspect ratio that matches the monitor. | ||
897 | |||
898 | //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has | ||
899 | // been born out in my experience. | ||
900 | // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) | ||
901 | // The ordering of display list is a blind assumption though, so we should check for max values | ||
902 | // Things might be different on the Mac though, so I'll defer to MBW | ||
903 | |||
904 | // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution | ||
905 | // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. | ||
906 | |||
907 | if (mOverrideAspectRatio > 0.f) | ||
908 | { | ||
909 | return mOverrideAspectRatio; | ||
910 | } | ||
911 | |||
912 | return mOriginalAspectRatio; | ||
913 | } | ||
914 | |||
915 | F32 LLWindowSDL::getPixelAspectRatio() | ||
916 | { | ||
917 | F32 pixel_aspect = 1.f; | ||
918 | if (getFullscreen()) | ||
919 | { | ||
920 | LLCoordScreen screen_size; | ||
921 | getSize(&screen_size); | ||
922 | pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; | ||
923 | } | ||
924 | |||
925 | return pixel_aspect; | ||
926 | } | ||
927 | |||
928 | |||
929 | // some of this stuff is to support 'temporarily windowed' mode so that | ||
930 | // dialogs are still usable in fullscreen. HOWEVER! - it's not enabled/working | ||
931 | // yet. | ||
932 | static LLCoordScreen old_size; | ||
933 | static BOOL old_fullscreen; | ||
934 | void LLWindowSDL::beforeDialog() | ||
935 | { | ||
936 | llinfos << "LLWindowSDL::beforeDialog()" << llendl; | ||
937 | |||
938 | if (SDLReallyCaptureInput(FALSE) // must ungrab input so popup works! | ||
939 | && getSize(&old_size)) | ||
940 | { | ||
941 | old_fullscreen = was_fullscreen; | ||
942 | |||
943 | if (old_fullscreen) | ||
944 | { | ||
945 | // NOT YET WORKING | ||
946 | //switchContext(FALSE, old_size, TRUE); | ||
947 | } | ||
948 | } | ||
949 | |||
950 | #if LL_X11 | ||
951 | if (SDL_Display) | ||
952 | { | ||
953 | // Everything that we/SDL asked for should happen before we | ||
954 | // potentially hand control over to GTK. | ||
955 | XSync(SDL_Display, False); | ||
956 | } | ||
957 | #endif // LL_X11 | ||
958 | |||
959 | #if LL_GTK | ||
960 | // this is a good time to grab some GTK version information for | ||
961 | // diagnostics | ||
962 | maybe_do_gtk_diagnostics(); | ||
963 | #endif // LL_GTK | ||
964 | } | ||
965 | |||
966 | void LLWindowSDL::afterDialog() | ||
967 | { | ||
968 | llinfos << "LLWindowSDL::afterDialog()" << llendl; | ||
969 | if (old_fullscreen && !was_fullscreen) | ||
970 | { | ||
971 | // *FIX: NOT YET WORKING (see below) | ||
972 | //switchContext(TRUE, old_size, TRUE); | ||
973 | } | ||
974 | // *FIX: we need to restore the GL context using | ||
975 | // LLViewerWindow::restoreGL() - but how?? | ||
976 | } | ||
977 | |||
978 | |||
979 | S32 LLWindowSDL::stat(const char* file_name, struct stat* stat_info) | ||
980 | { | ||
981 | return ::stat( file_name, stat_info ); | ||
982 | } | ||
983 | |||
984 | #if LL_X11 | ||
985 | // set/reset the XWMHints flag for 'urgency' that usually makes the icon flash | ||
986 | void LLWindowSDL::x11_set_urgent(BOOL urgent) | ||
987 | { | ||
988 | if (SDL_Display && !mFullscreen) | ||
989 | { | ||
990 | XWMHints *wm_hints; | ||
991 | |||
992 | llinfos << "X11 hint for urgency, " << urgent << llendl; | ||
993 | |||
994 | wm_hints = XGetWMHints(SDL_Display, mSDL_XWindowID); | ||
995 | if (!wm_hints) | ||
996 | wm_hints = XAllocWMHints(); | ||
997 | |||
998 | if (urgent) | ||
999 | wm_hints->flags |= XUrgencyHint; | ||
1000 | else | ||
1001 | wm_hints->flags &= ~XUrgencyHint; | ||
1002 | |||
1003 | XSetWMHints(SDL_Display, mSDL_XWindowID, wm_hints); | ||
1004 | XFree(wm_hints); | ||
1005 | XSync(SDL_Display, False); | ||
1006 | } | ||
1007 | } | ||
1008 | #endif // LL_X11 | ||
1009 | |||
1010 | void LLWindowSDL::flashIcon(F32 seconds) | ||
1011 | { | ||
1012 | #if !LL_X11 | ||
1013 | llinfos << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << llendl; | ||
1014 | #else | ||
1015 | llinfos << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << llendl; | ||
1016 | |||
1017 | F32 remaining_time = mFlashTimer.getRemainingTimeF32(); | ||
1018 | if (remaining_time < seconds) | ||
1019 | remaining_time = seconds; | ||
1020 | mFlashTimer.reset(); | ||
1021 | mFlashTimer.setTimerExpirySec(remaining_time); | ||
1022 | |||
1023 | x11_set_urgent(TRUE); | ||
1024 | mFlashing = TRUE; | ||
1025 | #endif // LL_X11 | ||
1026 | } | ||
1027 | |||
1028 | #if LL_X11 | ||
1029 | /* Lots of low-level X11 stuff to handle X11 copy-and-paste */ | ||
1030 | |||
1031 | /* Our X11 clipboard support is a bit bizarre in various | ||
1032 | organically-grown ways. Ideally it should be fixed to do | ||
1033 | real string-type negotiation (this would make pasting to | ||
1034 | xterm faster and pasting to UTF-8 emacs work properly), but | ||
1035 | right now it has the rare and desirable trait of being | ||
1036 | generally stable and working. */ | ||
1037 | |||
1038 | /* PRIMARY and CLIPBOARD are the two main kinds of | ||
1039 | X11 clipboard. A third are the CUT_BUFFERs which an | ||
1040 | obsolete holdover from X10 days and use a quite orthogonal | ||
1041 | mechanism. CLIPBOARD is the type whose design most | ||
1042 | closely matches SL's own win32-alike explicit copy-and-paste | ||
1043 | paradigm. | ||
1044 | |||
1045 | Pragmatically we support all three to varying degrees. When | ||
1046 | we paste into SL, it is strictly from CLIPBOARD. When we copy, | ||
1047 | we support (to as full an extent as the clipboard content type | ||
1048 | allows) CLIPBOARD, PRIMARY, and CUT_BUFFER0. | ||
1049 | */ | ||
1050 | #define SL_READWRITE_XCLIPBOARD_TYPE XInternAtom(SDL_Display, "CLIPBOARD", False) | ||
1051 | #define SL_WRITE_XCLIPBOARD_TYPE XA_PRIMARY | ||
1052 | |||
1053 | /* This is where our own private cutbuffer goes - we don't use | ||
1054 | a regular cutbuffer (XA_CUT_BUFFER0 etc) for intermediate | ||
1055 | storage because their use isn't really defined for holding UTF8. */ | ||
1056 | #define SL_CUTBUFFER_TYPE XInternAtom(SDL_Display, "SECONDLIFE_CUTBUFFER", False) | ||
1057 | |||
1058 | /* These defines, and convert_data/convert_x11clipboard, | ||
1059 | mostly exist to support non-text or unusually-encoded | ||
1060 | clipboard data, which we don't really have a need for at | ||
1061 | the moment. */ | ||
1062 | #define SDLCLIPTYPE(A, B, C, D) (int)((A<<24)|(B<<16)|(C<<8)|(D<<0)) | ||
1063 | #define FORMAT_PREFIX "SECONDLIFE_x11clipboard_0x" | ||
1064 | |||
1065 | typedef Atom x11clipboard_type; | ||
1066 | |||
1067 | static | ||
1068 | x11clipboard_type convert_format(int type) | ||
1069 | { | ||
1070 | switch (type) | ||
1071 | { | ||
1072 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | ||
1073 | // old-style X11 clipboard, strictly only ISO 8859-1 encoding | ||
1074 | return XA_STRING; | ||
1075 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | ||
1076 | // newer de-facto UTF8 clipboard atom | ||
1077 | return XInternAtom(SDL_Display, "UTF8_STRING", False); | ||
1078 | default: | ||
1079 | { | ||
1080 | /* completely arbitrary clipboard types... we don't actually use | ||
1081 | these right now, and support is skeletal. */ | ||
1082 | char format[sizeof(FORMAT_PREFIX)+8+1]; | ||
1083 | |||
1084 | sprintf(format, "%s%08lx", FORMAT_PREFIX, (unsigned long)type); | ||
1085 | return XInternAtom(SDL_Display, format, False); | ||
1086 | } | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | /* convert platform string to x11 clipboard format. for our | ||
1091 | purposes this is pretty trivial right now. */ | ||
1092 | static int | ||
1093 | convert_data(int type, char *dst, const char *src, int srclen) | ||
1094 | { | ||
1095 | int dstlen; | ||
1096 | |||
1097 | dstlen = 0; | ||
1098 | switch (type) | ||
1099 | { | ||
1100 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | ||
1101 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | ||
1102 | if ( srclen == 0 ) | ||
1103 | srclen = strlen(src); | ||
1104 | |||
1105 | dstlen = srclen + 1; | ||
1106 | |||
1107 | if ( dst ) // assume caller made it big enough by asking us | ||
1108 | { | ||
1109 | memcpy(dst, src, srclen); | ||
1110 | dst[srclen] = '\0'; | ||
1111 | } | ||
1112 | break; | ||
1113 | |||
1114 | default: | ||
1115 | llwarns << "convert_data: Unknown medium type" << llendl; | ||
1116 | break; | ||
1117 | } | ||
1118 | return(dstlen); | ||
1119 | } | ||
1120 | |||
1121 | /* Convert x11clipboard data to platform string. This too is | ||
1122 | pretty trivial for our needs right now, and just about identical | ||
1123 | to above. */ | ||
1124 | static int | ||
1125 | convert_x11clipboard(int type, char *dst, const char *src, int srclen) | ||
1126 | { | ||
1127 | int dstlen; | ||
1128 | |||
1129 | dstlen = 0; | ||
1130 | switch (type) | ||
1131 | { | ||
1132 | case SDLCLIPTYPE('U', 'T', 'F', '8'): | ||
1133 | case SDLCLIPTYPE('T', 'E', 'X', 'T'): | ||
1134 | if ( srclen == 0 ) | ||
1135 | srclen = strlen(src); | ||
1136 | |||
1137 | dstlen = srclen + 1; | ||
1138 | |||
1139 | if ( dst ) // assume caller made it big enough by asking us | ||
1140 | { | ||
1141 | memcpy(dst, src, srclen); | ||
1142 | dst[srclen] = '\0'; | ||
1143 | } | ||
1144 | break; | ||
1145 | |||
1146 | default: | ||
1147 | llwarns << "convert_x11clipboard: Unknown medium type" << llendl; | ||
1148 | break; | ||
1149 | } | ||
1150 | return dstlen; | ||
1151 | } | ||
1152 | |||
1153 | int | ||
1154 | LLWindowSDL::is_empty_x11clipboard(void) | ||
1155 | { | ||
1156 | int retval; | ||
1157 | |||
1158 | Lock_Display(); | ||
1159 | retval = ( XGetSelectionOwner(SDL_Display, SL_READWRITE_XCLIPBOARD_TYPE) == None ); | ||
1160 | Unlock_Display(); | ||
1161 | |||
1162 | return(retval); | ||
1163 | } | ||
1164 | |||
1165 | void | ||
1166 | LLWindowSDL::put_x11clipboard(int type, int srclen, const char *src) | ||
1167 | { | ||
1168 | x11clipboard_type format; | ||
1169 | int dstlen; | ||
1170 | char *dst; | ||
1171 | |||
1172 | format = convert_format(type); | ||
1173 | dstlen = convert_data(type, NULL, src, srclen); | ||
1174 | |||
1175 | dst = (char *)malloc(dstlen); | ||
1176 | if ( dst != NULL ) | ||
1177 | { | ||
1178 | Window root = DefaultRootWindow(SDL_Display); | ||
1179 | Lock_Display(); | ||
1180 | convert_data(type, dst, src, srclen); | ||
1181 | // Cutbuffers are only allowed to have STRING atom types, | ||
1182 | // but Emacs puts UTF8 inside them anyway. We cautiously | ||
1183 | // don't. | ||
1184 | if (type == SDLCLIPTYPE('T','E','X','T')) | ||
1185 | { | ||
1186 | // dstlen-1 so we don't include the trailing \0 | ||
1187 | llinfos << "X11: Populating cutbuffer." <<llendl; | ||
1188 | XChangeProperty(SDL_Display, root, | ||
1189 | XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace, | ||
1190 | (unsigned char*)dst, dstlen-1); | ||
1191 | } else { | ||
1192 | // Should we clear the cutbuffer if we can't put the selection in | ||
1193 | // it because it's a UTF8 selection? Eh, no great reason I think. | ||
1194 | //XDeleteProperty(SDL_Display, root, XA_CUT_BUFFER0); | ||
1195 | } | ||
1196 | // Private cutbuffer of an appropriate type. | ||
1197 | XChangeProperty(SDL_Display, root, | ||
1198 | SL_CUTBUFFER_TYPE, format, 8, PropModeReplace, | ||
1199 | (unsigned char*)dst, dstlen-1); | ||
1200 | free(dst); | ||
1201 | |||
1202 | /* Claim ownership of both PRIMARY and CLIPBOARD */ | ||
1203 | XSetSelectionOwner(SDL_Display, SL_READWRITE_XCLIPBOARD_TYPE, | ||
1204 | mSDL_XWindowID, CurrentTime); | ||
1205 | XSetSelectionOwner(SDL_Display, SL_WRITE_XCLIPBOARD_TYPE, | ||
1206 | mSDL_XWindowID, CurrentTime); | ||
1207 | |||
1208 | Unlock_Display(); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | void | ||
1213 | LLWindowSDL::get_x11clipboard(int type, int *dstlen, char **dst) | ||
1214 | { | ||
1215 | x11clipboard_type format; | ||
1216 | |||
1217 | *dstlen = 0; | ||
1218 | format = convert_format(type); | ||
1219 | |||
1220 | Window owner; | ||
1221 | Atom selection; | ||
1222 | Atom seln_type; | ||
1223 | int seln_format; | ||
1224 | unsigned long nbytes; | ||
1225 | unsigned long overflow; | ||
1226 | char *src; | ||
1227 | |||
1228 | Lock_Display(); | ||
1229 | owner = XGetSelectionOwner(SDL_Display, SL_READWRITE_XCLIPBOARD_TYPE); | ||
1230 | Unlock_Display(); | ||
1231 | if (owner == None) | ||
1232 | { | ||
1233 | // Fall right back to ancient X10 cut-buffers | ||
1234 | owner = DefaultRootWindow(SDL_Display); | ||
1235 | selection = XA_CUT_BUFFER0; | ||
1236 | } else if (owner == mSDL_XWindowID) | ||
1237 | { | ||
1238 | // Use our own uncooked opaque string property | ||
1239 | owner = DefaultRootWindow(SDL_Display); | ||
1240 | selection = SL_CUTBUFFER_TYPE; | ||
1241 | } | ||
1242 | else | ||
1243 | { | ||
1244 | // Use full-on X11-style clipboard negotiation with the owning app | ||
1245 | int selection_response = 0; | ||
1246 | SDL_Event event; | ||
1247 | |||
1248 | owner = mSDL_XWindowID; | ||
1249 | Lock_Display(); | ||
1250 | selection = XInternAtom(SDL_Display, "SDL_SELECTION", False); | ||
1251 | XConvertSelection(SDL_Display, SL_READWRITE_XCLIPBOARD_TYPE, format, | ||
1252 | selection, owner, CurrentTime); | ||
1253 | Unlock_Display(); | ||
1254 | llinfos << "X11: Waiting for clipboard to arrive." <<llendl; | ||
1255 | while ( ! selection_response ) | ||
1256 | { | ||
1257 | // Only look for SYSWMEVENTs, or we may lose keypresses | ||
1258 | // etc. | ||
1259 | SDL_PumpEvents(); | ||
1260 | if (1 == SDL_PeepEvents(&event, 1, SDL_GETEVENT, | ||
1261 | SDL_SYSWMEVENTMASK) ) | ||
1262 | { | ||
1263 | if ( event.type == SDL_SYSWMEVENT ) | ||
1264 | { | ||
1265 | XEvent xevent = | ||
1266 | event.syswm.msg->event.xevent; | ||
1267 | |||
1268 | if ( (xevent.type == SelectionNotify)&& | ||
1269 | (xevent.xselection.requestor == owner) ) | ||
1270 | selection_response = 1; | ||
1271 | } | ||
1272 | } else { | ||
1273 | llinfos << "X11: Waiting for SYSWM event..." << llendl; | ||
1274 | } | ||
1275 | } | ||
1276 | llinfos << "X11: Clipboard arrived." <<llendl; | ||
1277 | } | ||
1278 | |||
1279 | Lock_Display(); | ||
1280 | if ( XGetWindowProperty(SDL_Display, owner, selection, 0, INT_MAX/4, | ||
1281 | False, format, &seln_type, &seln_format, | ||
1282 | &nbytes, &overflow, (unsigned char **)&src) == Success ) | ||
1283 | { | ||
1284 | if ( seln_type == format ) | ||
1285 | { | ||
1286 | *dstlen = convert_x11clipboard(type, NULL, src, nbytes); | ||
1287 | *dst = (char *)realloc(*dst, *dstlen); | ||
1288 | if ( *dst == NULL ) | ||
1289 | *dstlen = 0; | ||
1290 | else | ||
1291 | convert_x11clipboard(type, *dst, src, nbytes); | ||
1292 | } | ||
1293 | XFree(src); | ||
1294 | } | ||
1295 | |||
1296 | Unlock_Display(); | ||
1297 | } | ||
1298 | |||
1299 | int clipboard_filter_callback(const SDL_Event *event) | ||
1300 | { | ||
1301 | /* Post all non-window manager specific events */ | ||
1302 | if ( event->type != SDL_SYSWMEVENT ) | ||
1303 | { | ||
1304 | return(1); | ||
1305 | } | ||
1306 | |||
1307 | /* Handle window-manager specific clipboard events */ | ||
1308 | switch (event->syswm.msg->event.xevent.type) { | ||
1309 | /* Copy the selection from SL_CUTBUFFER_TYPE to the requested property */ | ||
1310 | case SelectionRequest: { | ||
1311 | XSelectionRequestEvent *req; | ||
1312 | XEvent sevent; | ||
1313 | int seln_format; | ||
1314 | unsigned long nbytes; | ||
1315 | unsigned long overflow; | ||
1316 | unsigned char *seln_data; | ||
1317 | |||
1318 | req = &event->syswm.msg->event.xevent.xselectionrequest; | ||
1319 | sevent.xselection.type = SelectionNotify; | ||
1320 | sevent.xselection.display = req->display; | ||
1321 | sevent.xselection.selection = req->selection; | ||
1322 | sevent.xselection.target = None; | ||
1323 | sevent.xselection.property = None; | ||
1324 | sevent.xselection.requestor = req->requestor; | ||
1325 | sevent.xselection.time = req->time; | ||
1326 | if ( XGetWindowProperty(SDL_Display, DefaultRootWindow(SDL_Display), | ||
1327 | SL_CUTBUFFER_TYPE, 0, INT_MAX/4, False, req->target, | ||
1328 | &sevent.xselection.target, &seln_format, | ||
1329 | &nbytes, &overflow, &seln_data) == Success ) | ||
1330 | { | ||
1331 | if ( sevent.xselection.target == req->target) | ||
1332 | { | ||
1333 | if ( sevent.xselection.target == XA_STRING || | ||
1334 | sevent.xselection.target == | ||
1335 | convert_format(SDLCLIPTYPE('U','T','F','8')) ) | ||
1336 | { | ||
1337 | if ( seln_data[nbytes-1] == '\0' ) | ||
1338 | --nbytes; | ||
1339 | } | ||
1340 | XChangeProperty(SDL_Display, req->requestor, req->property, | ||
1341 | req->target, seln_format, PropModeReplace, | ||
1342 | seln_data, nbytes); | ||
1343 | sevent.xselection.property = req->property; | ||
1344 | #define XA_TARGETS XInternAtom(SDL_Display, "TARGETS", False) | ||
1345 | } else if (XA_TARGETS == req->target) { | ||
1346 | /* only advertise what we currently support */ | ||
1347 | const int num_supported = 3; | ||
1348 | Atom supported[num_supported] = { | ||
1349 | XA_STRING, // will be over-written below | ||
1350 | XInternAtom(SDL_Display, "TEXT",False), | ||
1351 | XA_TARGETS | ||
1352 | }; | ||
1353 | supported[0] = sevent.xselection.target; | ||
1354 | XChangeProperty(SDL_Display, req->requestor, | ||
1355 | req->property, XA_ATOM, 32, PropModeReplace, | ||
1356 | (unsigned char*)supported, | ||
1357 | num_supported); | ||
1358 | sevent.xselection.property = req->property; | ||
1359 | llinfos << "Clipboard: An app asked us what selections format we offer." << llendl; | ||
1360 | } else { | ||
1361 | llinfos << "Clipboard: An app requested an unsupported selection format " << req->target << ", we have " << sevent.xselection.target << llendl; | ||
1362 | sevent.xselection.target = None; | ||
1363 | } | ||
1364 | XFree(seln_data); | ||
1365 | } | ||
1366 | int sendret = | ||
1367 | XSendEvent(SDL_Display,req->requestor,False,0,&sevent); | ||
1368 | if ((sendret==BadValue) || (sendret==BadWindow)) | ||
1369 | llwarns << "Clipboard SendEvent failed" << llendl; | ||
1370 | XSync(SDL_Display, False); | ||
1371 | } | ||
1372 | break; | ||
1373 | } | ||
1374 | |||
1375 | /* Post the event for X11 clipboard reading above */ | ||
1376 | return(1); | ||
1377 | } | ||
1378 | |||
1379 | int | ||
1380 | LLWindowSDL::init_x11clipboard(void) | ||
1381 | { | ||
1382 | SDL_SysWMinfo info; | ||
1383 | int retval; | ||
1384 | |||
1385 | /* Grab the window manager specific information */ | ||
1386 | retval = -1; | ||
1387 | SDL_SetError("SDL is not running on known window manager"); | ||
1388 | |||
1389 | SDL_VERSION(&info.version); | ||
1390 | if ( SDL_GetWMInfo(&info) ) | ||
1391 | { | ||
1392 | /* Save the information for later use */ | ||
1393 | if ( info.subsystem == SDL_SYSWM_X11 ) | ||
1394 | { | ||
1395 | SDL_Display = info.info.x11.display; | ||
1396 | SDL_XWindowID = info.info.x11.wmwindow; | ||
1397 | mSDL_XWindowID = info.info.x11.wmwindow; | ||
1398 | Lock_Display = info.info.x11.lock_func; | ||
1399 | Unlock_Display = info.info.x11.unlock_func; | ||
1400 | |||
1401 | /* Enable the special window hook events */ | ||
1402 | SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); | ||
1403 | SDL_SetEventFilter(clipboard_filter_callback); | ||
1404 | |||
1405 | retval = 0; | ||
1406 | } | ||
1407 | else | ||
1408 | { | ||
1409 | SDL_SetError("SDL is not running on X11"); | ||
1410 | } | ||
1411 | } | ||
1412 | return(retval); | ||
1413 | } | ||
1414 | |||
1415 | void | ||
1416 | LLWindowSDL::quit_x11clipboard(void) | ||
1417 | { | ||
1418 | SDL_Display = NULL; | ||
1419 | SDL_XWindowID = None; | ||
1420 | mSDL_XWindowID = None; | ||
1421 | Lock_Display = NULL; | ||
1422 | Unlock_Display = NULL; | ||
1423 | |||
1424 | SDL_SetEventFilter(NULL); // Stop custom event filtering | ||
1425 | } | ||
1426 | |||
1427 | /************************************************/ | ||
1428 | |||
1429 | BOOL LLWindowSDL::isClipboardTextAvailable() | ||
1430 | { | ||
1431 | return !is_empty_x11clipboard(); | ||
1432 | } | ||
1433 | |||
1434 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) | ||
1435 | { | ||
1436 | int cliplen; // seems 1 or 2 bytes longer than expected | ||
1437 | char *cliptext = NULL; | ||
1438 | get_x11clipboard(SDLCLIPTYPE('U','T','F','8'), &cliplen, &cliptext); | ||
1439 | if (cliptext) | ||
1440 | { | ||
1441 | llinfos << "X11: Got UTF8 clipboard text." << llendl; | ||
1442 | // at some future time we can use cliplen instead of relying on \0, | ||
1443 | // if we ever grok non-ascii, non-utf8 encodings on the clipboard. | ||
1444 | std::string clip_str(cliptext); | ||
1445 | // we can't necessarily trust the incoming text to be valid UTF-8, | ||
1446 | // but utf8str_to_wstring() seems to do an appropriate level of | ||
1447 | // validation for avoiding over-reads. | ||
1448 | dst = utf8str_to_wstring(clip_str); | ||
1449 | /*llinfos << "X11 pasteTextFromClipboard: cliplen=" << cliplen << | ||
1450 | " strlen(cliptext)=" << strlen(cliptext) << | ||
1451 | " clip_str.length()=" << clip_str.length() << | ||
1452 | " dst.length()=" << dst.length() << | ||
1453 | llendl;*/ | ||
1454 | free(cliptext); | ||
1455 | return TRUE; // success | ||
1456 | } | ||
1457 | get_x11clipboard(SDLCLIPTYPE('T','E','X','T'), &cliplen, &cliptext); | ||
1458 | if (cliptext) | ||
1459 | { | ||
1460 | llinfos << "X11: Got ISO 8859-1 clipboard text." << llendl; | ||
1461 | std::string clip_str(cliptext); | ||
1462 | std::string utf8_str = rawstr_to_utf8(clip_str); | ||
1463 | dst = utf8str_to_wstring(utf8_str); | ||
1464 | free(cliptext); | ||
1465 | } | ||
1466 | return FALSE; // failure | ||
1467 | } | ||
1468 | |||
1469 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) | ||
1470 | { | ||
1471 | std::string utf8text = wstring_to_utf8str(s); | ||
1472 | const char* cstr = utf8text.c_str(); | ||
1473 | int cstrlen = strlen(cstr); | ||
1474 | int i; | ||
1475 | for (i=0; i<cstrlen; ++i) | ||
1476 | { | ||
1477 | if (0x80 & (unsigned char)cstr[i]) | ||
1478 | { | ||
1479 | // Found an 8-bit character; use new-style UTF8 clipboard | ||
1480 | llinfos << "X11: UTF8 copyTextToClipboard" << llendl; | ||
1481 | put_x11clipboard(SDLCLIPTYPE('U','T','F','8'), cstrlen, cstr); | ||
1482 | return TRUE; | ||
1483 | } | ||
1484 | } | ||
1485 | // Didn't find any 8-bit characters; use old-style ISO 8859-1 clipboard | ||
1486 | llinfos << "X11: ISO 8859-1 copyTextToClipboard" << llendl; | ||
1487 | put_x11clipboard(SDLCLIPTYPE('T','E','X','T'), cstrlen, cstr); | ||
1488 | return TRUE; | ||
1489 | } | ||
1490 | #else | ||
1491 | |||
1492 | BOOL LLWindowSDL::isClipboardTextAvailable() | ||
1493 | { | ||
1494 | return FALSE; // unsupported | ||
1495 | } | ||
1496 | |||
1497 | BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) | ||
1498 | { | ||
1499 | return FALSE; // unsupported | ||
1500 | } | ||
1501 | |||
1502 | BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) | ||
1503 | { | ||
1504 | return FALSE; // unsupported | ||
1505 | } | ||
1506 | #endif // LL_X11 | ||
1507 | |||
1508 | BOOL LLWindowSDL::sendEmail(const char* address, const char* subject, const char* body_text, | ||
1509 | const char* attachment, const char* attachment_displayed_name ) | ||
1510 | { | ||
1511 | // MBW -- XXX -- Um... yeah. I'll get to this later. | ||
1512 | |||
1513 | return FALSE; | ||
1514 | } | ||
1515 | |||
1516 | |||
1517 | LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) | ||
1518 | { | ||
1519 | if (!mSupportedResolutions) | ||
1520 | { | ||
1521 | mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; | ||
1522 | mNumSupportedResolutions = 0; | ||
1523 | |||
1524 | SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); | ||
1525 | if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) | ||
1526 | { | ||
1527 | int count = 0; | ||
1528 | while (*modes) // they're sorted biggest to smallest, so find end... | ||
1529 | { | ||
1530 | modes++; | ||
1531 | count++; | ||
1532 | } | ||
1533 | |||
1534 | while (count--) | ||
1535 | { | ||
1536 | modes--; | ||
1537 | SDL_Rect *r = *modes; | ||
1538 | int w = r->w; | ||
1539 | int h = r->h; | ||
1540 | if ((w >= 800) && (h >= 600)) | ||
1541 | { | ||
1542 | // make sure we don't add the same resolution multiple times! | ||
1543 | if ( (mNumSupportedResolutions == 0) || | ||
1544 | ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && | ||
1545 | (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) | ||
1546 | { | ||
1547 | mSupportedResolutions[mNumSupportedResolutions].mWidth = w; | ||
1548 | mSupportedResolutions[mNumSupportedResolutions].mHeight = h; | ||
1549 | mNumSupportedResolutions++; | ||
1550 | } | ||
1551 | } | ||
1552 | } | ||
1553 | } | ||
1554 | } | ||
1555 | |||
1556 | num_resolutions = mNumSupportedResolutions; | ||
1557 | return mSupportedResolutions; | ||
1558 | } | ||
1559 | |||
1560 | BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) | ||
1561 | { | ||
1562 | if (!to) | ||
1563 | return FALSE; | ||
1564 | |||
1565 | to->mX = from.mX; | ||
1566 | to->mY = mWindow->h - from.mY - 1; | ||
1567 | |||
1568 | return TRUE; | ||
1569 | } | ||
1570 | |||
1571 | BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) | ||
1572 | { | ||
1573 | if (!to) | ||
1574 | return FALSE; | ||
1575 | |||
1576 | to->mX = from.mX; | ||
1577 | to->mY = mWindow->h - from.mY - 1; | ||
1578 | |||
1579 | return TRUE; | ||
1580 | } | ||
1581 | |||
1582 | BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) | ||
1583 | { | ||
1584 | if (!to) | ||
1585 | return FALSE; | ||
1586 | |||
1587 | // In the fullscreen case, window and screen coordinates are the same. | ||
1588 | to->mX = from.mX; | ||
1589 | to->mY = from.mY; | ||
1590 | return (TRUE); | ||
1591 | } | ||
1592 | |||
1593 | BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) | ||
1594 | { | ||
1595 | if (!to) | ||
1596 | return FALSE; | ||
1597 | |||
1598 | // In the fullscreen case, window and screen coordinates are the same. | ||
1599 | to->mX = from.mX; | ||
1600 | to->mY = from.mY; | ||
1601 | return (TRUE); | ||
1602 | } | ||
1603 | |||
1604 | BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) | ||
1605 | { | ||
1606 | LLCoordWindow window_coord; | ||
1607 | |||
1608 | return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); | ||
1609 | } | ||
1610 | |||
1611 | BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) | ||
1612 | { | ||
1613 | LLCoordWindow window_coord; | ||
1614 | |||
1615 | return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); | ||
1616 | } | ||
1617 | |||
1618 | |||
1619 | |||
1620 | |||
1621 | void LLWindowSDL::setupFailure(const char* text, const char* caption, U32 type) | ||
1622 | { | ||
1623 | destroyContext(); | ||
1624 | |||
1625 | OSMessageBox(text, caption, type); | ||
1626 | } | ||
1627 | |||
1628 | BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) | ||
1629 | { | ||
1630 | // note: this used to be safe to call nestedly, but in the | ||
1631 | // end that's not really a wise usage pattern, so don't. | ||
1632 | |||
1633 | if (capture) | ||
1634 | mReallyCapturedCount = 1; | ||
1635 | else | ||
1636 | mReallyCapturedCount = 0; | ||
1637 | |||
1638 | SDL_GrabMode wantmode, newmode; | ||
1639 | if (mReallyCapturedCount <= 0) // uncapture | ||
1640 | { | ||
1641 | wantmode = SDL_GRAB_OFF; | ||
1642 | } else // capture | ||
1643 | { | ||
1644 | wantmode = SDL_GRAB_ON; | ||
1645 | } | ||
1646 | |||
1647 | if (mReallyCapturedCount < 0) // yuck, imbalance. | ||
1648 | { | ||
1649 | mReallyCapturedCount = 0; | ||
1650 | llwarns << "ReallyCapture count was < 0" << llendl; | ||
1651 | } | ||
1652 | |||
1653 | if (!mFullscreen) /* only bother if we're windowed anyway */ | ||
1654 | { | ||
1655 | #if LL_X11 | ||
1656 | if (SDL_Display) | ||
1657 | { | ||
1658 | /* we dirtily mix raw X11 with SDL so that our pointer | ||
1659 | isn't (as often) constrained to the limits of the | ||
1660 | window while grabbed, which feels nicer and | ||
1661 | hopefully eliminates some reported 'sticky pointer' | ||
1662 | problems. We use raw X11 instead of | ||
1663 | SDL_WM_GrabInput() because the latter constrains | ||
1664 | the pointer to the window and also steals all | ||
1665 | *keyboard* input from the window manager, which was | ||
1666 | frustrating users. */ | ||
1667 | int result; | ||
1668 | if (wantmode == SDL_GRAB_ON) | ||
1669 | { | ||
1670 | //llinfos << "X11 POINTER GRABBY" << llendl; | ||
1671 | //newmode = SDL_WM_GrabInput(wantmode); | ||
1672 | result = XGrabPointer(SDL_Display, mSDL_XWindowID, | ||
1673 | True, 0, GrabModeAsync, | ||
1674 | GrabModeAsync, | ||
1675 | None, None, CurrentTime); | ||
1676 | if (GrabSuccess == result) | ||
1677 | newmode = SDL_GRAB_ON; | ||
1678 | else | ||
1679 | newmode = SDL_GRAB_OFF; | ||
1680 | } else if (wantmode == SDL_GRAB_OFF) | ||
1681 | { | ||
1682 | //llinfos << "X11 POINTER UNGRABBY" << llendl; | ||
1683 | newmode = SDL_GRAB_OFF; | ||
1684 | //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); | ||
1685 | |||
1686 | XUngrabPointer(SDL_Display, CurrentTime); | ||
1687 | // Make sure the ungrab happens RIGHT NOW. | ||
1688 | XSync(SDL_Display, False); | ||
1689 | } else | ||
1690 | { | ||
1691 | newmode = SDL_GRAB_QUERY; // neutral | ||
1692 | } | ||
1693 | } else // not actually running on X11, for some reason | ||
1694 | newmode = wantmode; | ||
1695 | #endif // LL_X11 | ||
1696 | } else { | ||
1697 | // pretend we got what we wanted, when really we don't care. | ||
1698 | newmode = wantmode; | ||
1699 | } | ||
1700 | |||
1701 | // return boolean success for whether we ended up in the desired state | ||
1702 | return (capture && SDL_GRAB_ON==newmode) || | ||
1703 | (!capture && SDL_GRAB_OFF==newmode); | ||
1704 | } | ||
1705 | |||
1706 | U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain) | ||
1707 | { | ||
1708 | /* part of the fix for SL-13243: Some popular window managers like | ||
1709 | to totally eat alt-drag for the purposes of moving windows. We | ||
1710 | spoil their day by acquiring the exclusive X11 mouse lock for as | ||
1711 | long as LALT is held down, so the window manager can't easily | ||
1712 | see what's happening. Tested successfully with Metacity. | ||
1713 | And... do the same with CTRL, for other darn WMs. We don't | ||
1714 | care about other metakeys as SL doesn't use them with dragging | ||
1715 | (for now). */ | ||
1716 | |||
1717 | /* We maintain a bitmap of critical keys which are up and down | ||
1718 | instead of simply key-counting, because SDL sometimes reports | ||
1719 | misbalanced keyup/keydown event pairs to us for whatever reason. */ | ||
1720 | |||
1721 | U32 mask = 0; | ||
1722 | switch (keysym) | ||
1723 | { | ||
1724 | case SDLK_LALT: | ||
1725 | mask = 1U << 0; break; | ||
1726 | case SDLK_LCTRL: | ||
1727 | mask = 1U << 1; break; | ||
1728 | case SDLK_RCTRL: | ||
1729 | mask = 1U << 2; break; | ||
1730 | default: | ||
1731 | break; | ||
1732 | } | ||
1733 | |||
1734 | if (gain) | ||
1735 | mGrabbyKeyFlags |= mask; | ||
1736 | else | ||
1737 | mGrabbyKeyFlags &= ~mask; | ||
1738 | |||
1739 | //llinfos << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << llendl; | ||
1740 | |||
1741 | /* 0 means we don't need to mousegrab, otherwise grab. */ | ||
1742 | return mGrabbyKeyFlags; | ||
1743 | } | ||
1744 | |||
1745 | void LLWindowSDL::gatherInput() | ||
1746 | { | ||
1747 | const Uint32 CLICK_THRESHOLD = 300; // milliseconds | ||
1748 | static int leftClick = 0; | ||
1749 | static int rightClick = 0; | ||
1750 | static Uint32 lastLeftDown = 0; | ||
1751 | static Uint32 lastRightDown = 0; | ||
1752 | SDL_Event event; | ||
1753 | |||
1754 | while (SDL_PollEvent(&event)) | ||
1755 | { | ||
1756 | switch (event.type) | ||
1757 | { | ||
1758 | case SDL_MOUSEMOTION: | ||
1759 | { | ||
1760 | LLCoordWindow winCoord(event.button.x, event.button.y); | ||
1761 | LLCoordGL openGlCoord; | ||
1762 | convertCoords(winCoord, &openGlCoord); | ||
1763 | MASK mask = gKeyboard->currentMask(TRUE); | ||
1764 | mCallbacks->handleMouseMove(this, openGlCoord, mask); | ||
1765 | break; | ||
1766 | } | ||
1767 | |||
1768 | case SDL_KEYDOWN: | ||
1769 | gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); | ||
1770 | // part of the fix for SL-13243 | ||
1771 | if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) | ||
1772 | SDLReallyCaptureInput(TRUE); | ||
1773 | |||
1774 | if (event.key.keysym.unicode) | ||
1775 | mCallbacks->handleUnicodeChar(event.key.keysym.unicode, gKeyboard->currentMask(FALSE)); | ||
1776 | break; | ||
1777 | |||
1778 | case SDL_KEYUP: | ||
1779 | if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) | ||
1780 | SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 | ||
1781 | |||
1782 | // This is a testing hack to pop up a dialog when 4 is pressed | ||
1783 | //if (event.key.keysym.sym == SDLK_4) | ||
1784 | //OSMessageBox("a whole bunch of text goes right here, whee! test test test.", "this is the title!", OSMB_YESNO); | ||
1785 | |||
1786 | gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); | ||
1787 | break; | ||
1788 | |||
1789 | case SDL_MOUSEBUTTONDOWN: | ||
1790 | { | ||
1791 | bool isDoubleClick = false; | ||
1792 | LLCoordWindow winCoord(event.button.x, event.button.y); | ||
1793 | LLCoordGL openGlCoord; | ||
1794 | convertCoords(winCoord, &openGlCoord); | ||
1795 | MASK mask = gKeyboard->currentMask(TRUE); | ||
1796 | |||
1797 | if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... | ||
1798 | { | ||
1799 | Uint32 now = SDL_GetTicks(); | ||
1800 | if ((now - lastLeftDown) > CLICK_THRESHOLD) | ||
1801 | leftClick = 1; | ||
1802 | else | ||
1803 | { | ||
1804 | if (++leftClick >= 2) | ||
1805 | { | ||
1806 | leftClick = 0; | ||
1807 | isDoubleClick = true; | ||
1808 | } | ||
1809 | } | ||
1810 | lastLeftDown = now; | ||
1811 | } | ||
1812 | else if (event.button.button == SDL_BUTTON_RIGHT) | ||
1813 | { | ||
1814 | Uint32 now = SDL_GetTicks(); | ||
1815 | if ((now - lastRightDown) > CLICK_THRESHOLD) | ||
1816 | rightClick = 1; | ||
1817 | else | ||
1818 | { | ||
1819 | if (++rightClick >= 2) | ||
1820 | { | ||
1821 | rightClick = 0; | ||
1822 | isDoubleClick = true; | ||
1823 | } | ||
1824 | } | ||
1825 | lastRightDown = now; | ||
1826 | } | ||
1827 | |||
1828 | if (event.button.button == SDL_BUTTON_LEFT) // left | ||
1829 | { | ||
1830 | if (isDoubleClick) | ||
1831 | mCallbacks->handleDoubleClick(this, openGlCoord, mask); | ||
1832 | else | ||
1833 | mCallbacks->handleMouseDown(this, openGlCoord, mask); | ||
1834 | } | ||
1835 | |||
1836 | else if (event.button.button == SDL_BUTTON_RIGHT) // right ... yes, it's 3, not 2, in SDL... | ||
1837 | { | ||
1838 | // right double click isn't handled right now in Second Life ... if (isDoubleClick) | ||
1839 | mCallbacks->handleRightMouseDown(this, openGlCoord, mask); | ||
1840 | } | ||
1841 | |||
1842 | else if (event.button.button == SDL_BUTTON_MIDDLE) // middle | ||
1843 | ; // Middle mouse isn't handled right now in Second Life ... mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); | ||
1844 | else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". | ||
1845 | mCallbacks->handleScrollWheel(this, -1); | ||
1846 | else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". | ||
1847 | mCallbacks->handleScrollWheel(this, 1); | ||
1848 | |||
1849 | break; | ||
1850 | } | ||
1851 | |||
1852 | case SDL_MOUSEBUTTONUP: | ||
1853 | { | ||
1854 | LLCoordWindow winCoord(event.button.x, event.button.y); | ||
1855 | LLCoordGL openGlCoord; | ||
1856 | convertCoords(winCoord, &openGlCoord); | ||
1857 | MASK mask = gKeyboard->currentMask(TRUE); | ||
1858 | |||
1859 | if (event.button.button == SDL_BUTTON_LEFT) // left | ||
1860 | mCallbacks->handleMouseUp(this, openGlCoord, mask); | ||
1861 | else if (event.button.button == SDL_BUTTON_RIGHT) // right ... yes, it's 3, not 2, in SDL... | ||
1862 | mCallbacks->handleRightMouseUp(this, openGlCoord, mask); | ||
1863 | else if (event.button.button == SDL_BUTTON_MIDDLE) // middle | ||
1864 | ; // UNUSED IN SECOND LIFE RIGHT NOW mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); | ||
1865 | |||
1866 | // don't handle mousewheel here... | ||
1867 | |||
1868 | break; | ||
1869 | } | ||
1870 | |||
1871 | case SDL_VIDEOEXPOSE: // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! | ||
1872 | mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); | ||
1873 | break; | ||
1874 | |||
1875 | case SDL_VIDEORESIZE: // *FIX: handle this? | ||
1876 | llinfos << "Handling a resize event: " << event.resize.w << | ||
1877 | "x" << event.resize.h << llendl; | ||
1878 | |||
1879 | // *FIX: I'm not sure this is necessary! | ||
1880 | mWindow = SDL_SetVideoMode(event.resize.w, event.resize.h, 32, mSDLFlags); | ||
1881 | if (!mWindow) | ||
1882 | { | ||
1883 | // *FIX: More informative dialog? | ||
1884 | llinfos << "Could not recreate context after resize! Quitting..." << llendl; | ||
1885 | if(mCallbacks->handleCloseRequest(this)) | ||
1886 | { | ||
1887 | // Get the app to initiate cleanup. | ||
1888 | mCallbacks->handleQuit(this); | ||
1889 | // The app is responsible for calling destroyWindow when done with GL | ||
1890 | } | ||
1891 | break; | ||
1892 | } | ||
1893 | |||
1894 | mCallbacks->handleResize(this, event.resize.w, event.resize.h ); | ||
1895 | break; | ||
1896 | |||
1897 | case SDL_ACTIVEEVENT: | ||
1898 | if (event.active.state & SDL_APPINPUTFOCUS) | ||
1899 | { | ||
1900 | // Note that for SDL (particularly on X11), keyboard | ||
1901 | // and mouse focus are independent things. Here we are | ||
1902 | // tracking keyboard focus state changes. | ||
1903 | |||
1904 | // We have to do our own state massaging because SDL | ||
1905 | // can send us two unfocus events in a row for example, | ||
1906 | // which confuses the focus code [SL-24071]. | ||
1907 | if (event.active.gain != mHaveInputFocus) | ||
1908 | { | ||
1909 | if (event.active.gain) | ||
1910 | mCallbacks->handleFocus(this); | ||
1911 | else | ||
1912 | mCallbacks->handleFocusLost(this); | ||
1913 | |||
1914 | mHaveInputFocus = !!event.active.gain; | ||
1915 | } | ||
1916 | } | ||
1917 | if (event.active.state & SDL_APPACTIVE) | ||
1918 | { | ||
1919 | // Change in iconification/minimization state. | ||
1920 | if ((!event.active.gain) != mIsMinimized) | ||
1921 | { | ||
1922 | mCallbacks->handleActivate(this, !!event.active.gain); | ||
1923 | llinfos << "SDL deiconification state switched to " << BOOL(event.active.gain) << llendl; | ||
1924 | |||
1925 | mIsMinimized = (!event.active.gain); | ||
1926 | } | ||
1927 | else | ||
1928 | { | ||
1929 | llinfos << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << llendl; | ||
1930 | } | ||
1931 | } | ||
1932 | break; | ||
1933 | |||
1934 | case SDL_QUIT: | ||
1935 | if(mCallbacks->handleCloseRequest(this)) | ||
1936 | { | ||
1937 | // Get the app to initiate cleanup. | ||
1938 | mCallbacks->handleQuit(this); | ||
1939 | // The app is responsible for calling destroyWindow when done with GL | ||
1940 | } | ||
1941 | break; | ||
1942 | default: | ||
1943 | //llinfos << "Unhandled SDL event type " << event.type << llendl; | ||
1944 | break; | ||
1945 | } | ||
1946 | } | ||
1947 | |||
1948 | #if LL_X11 | ||
1949 | // This is a good time to stop flashing the icon if our mFlashTimer has | ||
1950 | // expired. | ||
1951 | if (mFlashing && mFlashTimer.hasExpired()) | ||
1952 | { | ||
1953 | x11_set_urgent(FALSE); | ||
1954 | mFlashing = FALSE; | ||
1955 | } | ||
1956 | #endif // LL_X11 | ||
1957 | } | ||
1958 | |||
1959 | static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) | ||
1960 | { | ||
1961 | SDL_Cursor *sdlcursor = NULL; | ||
1962 | SDL_Surface *bmpsurface; | ||
1963 | |||
1964 | // Load cursor pixel data from BMP file | ||
1965 | bmpsurface = Load_BMP_Resource(filename); | ||
1966 | if (bmpsurface && bmpsurface->w%8==0) | ||
1967 | { | ||
1968 | SDL_Surface *cursurface; | ||
1969 | llinfos << "Loaded cursor file " << filename << " " | ||
1970 | << bmpsurface->w << "x" << bmpsurface->h << llendl; | ||
1971 | cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, | ||
1972 | bmpsurface->w, | ||
1973 | bmpsurface->h, | ||
1974 | 32, | ||
1975 | 0xFFU, | ||
1976 | 0xFF00U, | ||
1977 | 0xFF0000U, | ||
1978 | 0xFF000000U); | ||
1979 | SDL_FillRect(cursurface, NULL, 0x00000000U); | ||
1980 | |||
1981 | // Blit the cursor pixel data onto a 32-bit RGBA surface so we | ||
1982 | // only have to cope with processing one type of pixel format. | ||
1983 | if (0 == SDL_BlitSurface(bmpsurface, NULL, | ||
1984 | cursurface, NULL)) | ||
1985 | { | ||
1986 | // n.b. we already checked that width is a multiple of 8. | ||
1987 | const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; | ||
1988 | unsigned char *cursor_data = new unsigned char[bitmap_bytes]; | ||
1989 | unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; | ||
1990 | memset(cursor_data, 0, bitmap_bytes); | ||
1991 | memset(cursor_mask, 0, bitmap_bytes); | ||
1992 | int i,j; | ||
1993 | // Walk the RGBA cursor pixel data, extracting both data and | ||
1994 | // mask to build SDL-friendly cursor bitmaps from. The mask | ||
1995 | // is inferred by color-keying against 200,200,200 | ||
1996 | for (i=0; i<cursurface->h; ++i) { | ||
1997 | for (j=0; j<cursurface->w; ++j) { | ||
1998 | unsigned char *pixelp = | ||
1999 | ((unsigned char *)cursurface->pixels) | ||
2000 | + cursurface->pitch * i | ||
2001 | + j*cursurface->format->BytesPerPixel; | ||
2002 | unsigned char srcred = pixelp[0]; | ||
2003 | unsigned char srcgreen = pixelp[1]; | ||
2004 | unsigned char srcblue = pixelp[2]; | ||
2005 | BOOL mask_bit = (srcred != 200) | ||
2006 | || (srcgreen != 200) | ||
2007 | || (srcblue != 200); | ||
2008 | BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80 | ||
2009 | unsigned char bit_offset = (cursurface->w/8) * i | ||
2010 | + j/8; | ||
2011 | cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); | ||
2012 | cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7)); | ||
2013 | } | ||
2014 | } | ||
2015 | sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, | ||
2016 | (Uint8*)cursor_mask, | ||
2017 | cursurface->w, cursurface->h, | ||
2018 | hotx, hoty); | ||
2019 | delete[] cursor_data; | ||
2020 | delete[] cursor_mask; | ||
2021 | } else { | ||
2022 | llwarns << "CURSOR BLIT FAILURE, cursurface: " << cursurface << llendl; | ||
2023 | } | ||
2024 | SDL_FreeSurface(cursurface); | ||
2025 | SDL_FreeSurface(bmpsurface); | ||
2026 | } else { | ||
2027 | llwarns << "CURSOR LOAD FAILURE " << filename << llendl; | ||
2028 | } | ||
2029 | |||
2030 | return sdlcursor; | ||
2031 | } | ||
2032 | |||
2033 | void LLWindowSDL::setCursor(ECursorType cursor) | ||
2034 | { | ||
2035 | if (mCurrentCursor != cursor) | ||
2036 | { | ||
2037 | if (cursor < UI_CURSOR_COUNT) | ||
2038 | { | ||
2039 | SDL_Cursor *sdlcursor = mSDLCursors[cursor]; | ||
2040 | // Try to default to the arrow for any cursors that | ||
2041 | // did not load correctly. | ||
2042 | if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) | ||
2043 | sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; | ||
2044 | if (sdlcursor) | ||
2045 | SDL_SetCursor(sdlcursor); | ||
2046 | } else { | ||
2047 | llwarns << "Tried to set invalid cursor number " << cursor << llendl; | ||
2048 | } | ||
2049 | mCurrentCursor = cursor; | ||
2050 | } | ||
2051 | } | ||
2052 | |||
2053 | ECursorType LLWindowSDL::getCursor() | ||
2054 | { | ||
2055 | return mCurrentCursor; | ||
2056 | } | ||
2057 | |||
2058 | void LLWindowSDL::initCursors() | ||
2059 | { | ||
2060 | int i; | ||
2061 | // Blank the cursor pointer array for those we may miss. | ||
2062 | for (i=0; i<UI_CURSOR_COUNT; ++i) | ||
2063 | { | ||
2064 | mSDLCursors[i] = NULL; | ||
2065 | } | ||
2066 | // Pre-make an SDL cursor for each of the known cursor types. | ||
2067 | // We hardcode the hotspots - to avoid that we'd have to write | ||
2068 | // a .cur file loader. | ||
2069 | // NOTE: SDL doesn't load RLE-compressed BMP files. | ||
2070 | mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); | ||
2071 | mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); | ||
2072 | mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); | ||
2073 | mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); | ||
2074 | mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); | ||
2075 | mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); | ||
2076 | mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); | ||
2077 | mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); | ||
2078 | mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16); | ||
2079 | mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); | ||
2080 | mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); | ||
2081 | mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); | ||
2082 | mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); | ||
2083 | mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); | ||
2084 | mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7); | ||
2085 | mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0); | ||
2086 | mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0); | ||
2087 | mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0); | ||
2088 | mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0); | ||
2089 | mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8); | ||
2090 | mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0); | ||
2091 | mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13); | ||
2092 | mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0); | ||
2093 | mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0); | ||
2094 | mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0); | ||
2095 | mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5); | ||
2096 | mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); | ||
2097 | mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5); | ||
2098 | mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); | ||
2099 | mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",0,0); | ||
2100 | mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",0,0); | ||
2101 | mSDLCursors[UI_CURSOR_TOOLPAY] = makeSDLCursorFromBMP("toolpay.BMP",0,0); | ||
2102 | mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",0,0); | ||
2103 | mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28); | ||
2104 | } | ||
2105 | |||
2106 | void LLWindowSDL::quitCursors() | ||
2107 | { | ||
2108 | int i; | ||
2109 | if (mWindow) | ||
2110 | { | ||
2111 | for (i=0; i<UI_CURSOR_COUNT; ++i) | ||
2112 | { | ||
2113 | if (mSDLCursors[i]) | ||
2114 | { | ||
2115 | SDL_FreeCursor(mSDLCursors[i]); | ||
2116 | mSDLCursors[i] = NULL; | ||
2117 | } | ||
2118 | } | ||
2119 | } else { | ||
2120 | // SDL doesn't refcount cursors, so if the window has | ||
2121 | // already been destroyed then the cursors have gone with it. | ||
2122 | llinfos << "Skipping quitCursors: mWindow already gone." << llendl; | ||
2123 | for (i=0; i<UI_CURSOR_COUNT; ++i) | ||
2124 | mSDLCursors[i] = NULL; | ||
2125 | } | ||
2126 | } | ||
2127 | |||
2128 | void LLWindowSDL::captureMouse() | ||
2129 | { | ||
2130 | // SDL already enforces the semantics that captureMouse is | ||
2131 | // used for, i.e. that we continue to get mouse events as long | ||
2132 | // as a button is down regardless of whether we left the | ||
2133 | // window, and in a less obnoxious way than SDL_WM_GrabInput | ||
2134 | // which would confine the cursor to the window too. | ||
2135 | |||
2136 | //llinfos << "LLWindowSDL::captureMouse" << llendl; | ||
2137 | } | ||
2138 | |||
2139 | void LLWindowSDL::releaseMouse() | ||
2140 | { | ||
2141 | // see LWindowSDL::captureMouse() | ||
2142 | |||
2143 | //llinfos << "LLWindowSDL::releaseMouse" << llendl; | ||
2144 | } | ||
2145 | |||
2146 | void LLWindowSDL::hideCursor() | ||
2147 | { | ||
2148 | if(!mCursorHidden) | ||
2149 | { | ||
2150 | // llinfos << "hideCursor: hiding" << llendl; | ||
2151 | mCursorHidden = TRUE; | ||
2152 | mHideCursorPermanent = TRUE; | ||
2153 | SDL_ShowCursor(0); | ||
2154 | } | ||
2155 | else | ||
2156 | { | ||
2157 | // llinfos << "hideCursor: already hidden" << llendl; | ||
2158 | } | ||
2159 | |||
2160 | adjustCursorDecouple(); | ||
2161 | } | ||
2162 | |||
2163 | void LLWindowSDL::showCursor() | ||
2164 | { | ||
2165 | if(mCursorHidden) | ||
2166 | { | ||
2167 | // llinfos << "showCursor: showing" << llendl; | ||
2168 | mCursorHidden = FALSE; | ||
2169 | mHideCursorPermanent = FALSE; | ||
2170 | SDL_ShowCursor(1); | ||
2171 | } | ||
2172 | else | ||
2173 | { | ||
2174 | // llinfos << "showCursor: already visible" << llendl; | ||
2175 | } | ||
2176 | |||
2177 | adjustCursorDecouple(); | ||
2178 | } | ||
2179 | |||
2180 | void LLWindowSDL::showCursorFromMouseMove() | ||
2181 | { | ||
2182 | if (!mHideCursorPermanent) | ||
2183 | { | ||
2184 | showCursor(); | ||
2185 | } | ||
2186 | } | ||
2187 | |||
2188 | void LLWindowSDL::hideCursorUntilMouseMove() | ||
2189 | { | ||
2190 | if (!mHideCursorPermanent) | ||
2191 | { | ||
2192 | hideCursor(); | ||
2193 | mHideCursorPermanent = FALSE; | ||
2194 | } | ||
2195 | } | ||
2196 | |||
2197 | |||
2198 | |||
2199 | // | ||
2200 | // LLSplashScreenSDL | ||
2201 | // | ||
2202 | LLSplashScreenSDL::LLSplashScreenSDL() | ||
2203 | { | ||
2204 | } | ||
2205 | |||
2206 | LLSplashScreenSDL::~LLSplashScreenSDL() | ||
2207 | { | ||
2208 | } | ||
2209 | |||
2210 | void LLSplashScreenSDL::showImpl() | ||
2211 | { | ||
2212 | } | ||
2213 | |||
2214 | void LLSplashScreenSDL::updateImpl(const char* mesg) | ||
2215 | { | ||
2216 | } | ||
2217 | |||
2218 | |||
2219 | void LLSplashScreenSDL::hideImpl() | ||
2220 | { | ||
2221 | } | ||
2222 | |||
2223 | |||
2224 | |||
2225 | #if LL_GTK | ||
2226 | static void response_callback (GtkDialog *dialog, | ||
2227 | gint arg1, | ||
2228 | gpointer user_data) | ||
2229 | { | ||
2230 | gint *response = (gint*)user_data; | ||
2231 | *response = arg1; | ||
2232 | gtk_widget_destroy(GTK_WIDGET(dialog)); | ||
2233 | gtk_main_quit(); | ||
2234 | } | ||
2235 | |||
2236 | S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type) | ||
2237 | { | ||
2238 | S32 rtn = OSBTN_CANCEL; | ||
2239 | |||
2240 | #if LL_GTK | ||
2241 | maybe_do_gtk_diagnostics(); | ||
2242 | #endif // LL_GTK | ||
2243 | |||
2244 | if(gWindowImplementation != NULL) | ||
2245 | gWindowImplementation->beforeDialog(); | ||
2246 | |||
2247 | gtk_disable_setlocale(); | ||
2248 | if (gtk_init_check(NULL, NULL) | ||
2249 | // We can NOT expect to combine GTK and SDL's aggressive fullscreen | ||
2250 | && ((NULL==gWindowImplementation) || (!was_fullscreen)) | ||
2251 | ) | ||
2252 | { | ||
2253 | GtkWidget *win = NULL; | ||
2254 | |||
2255 | llinfos << "Creating a dialog because we're in windowed mode and GTK is happy." << llendl; | ||
2256 | |||
2257 | GtkDialogFlags flags = GTK_DIALOG_MODAL; | ||
2258 | GtkMessageType messagetype; | ||
2259 | GtkButtonsType buttons; | ||
2260 | switch (type) | ||
2261 | { | ||
2262 | default: | ||
2263 | case OSMB_OK: | ||
2264 | messagetype = GTK_MESSAGE_WARNING; | ||
2265 | buttons = GTK_BUTTONS_OK; | ||
2266 | break; | ||
2267 | case OSMB_OKCANCEL: | ||
2268 | messagetype = GTK_MESSAGE_QUESTION; | ||
2269 | buttons = GTK_BUTTONS_OK_CANCEL; | ||
2270 | break; | ||
2271 | case OSMB_YESNO: | ||
2272 | messagetype = GTK_MESSAGE_QUESTION; | ||
2273 | buttons = GTK_BUTTONS_YES_NO; | ||
2274 | break; | ||
2275 | } | ||
2276 | win = gtk_message_dialog_new(NULL, | ||
2277 | flags, messagetype, buttons, | ||
2278 | text); | ||
2279 | |||
2280 | # if LL_X11 | ||
2281 | // Make GTK tell the window manager to associate this | ||
2282 | // dialog with our non-GTK SDL window, which should try | ||
2283 | // to keep it on top etc. | ||
2284 | if (SDL_XWindowID != None) | ||
2285 | { | ||
2286 | gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin | ||
2287 | GdkWindow *gdkwin = gdk_window_foreign_new(SDL_XWindowID); | ||
2288 | gdk_window_set_transient_for(GTK_WIDGET(win)->window, | ||
2289 | gdkwin); | ||
2290 | } | ||
2291 | # endif //LL_X11 | ||
2292 | |||
2293 | gtk_window_set_position(GTK_WINDOW(win), | ||
2294 | GTK_WIN_POS_CENTER_ON_PARENT); | ||
2295 | |||
2296 | gtk_window_set_type_hint(GTK_WINDOW(win), | ||
2297 | GDK_WINDOW_TYPE_HINT_DIALOG); | ||
2298 | |||
2299 | if (caption) | ||
2300 | gtk_window_set_title(GTK_WINDOW(win), caption); | ||
2301 | |||
2302 | gint response = GTK_RESPONSE_NONE; | ||
2303 | g_signal_connect (win, | ||
2304 | "response", | ||
2305 | G_CALLBACK (response_callback), | ||
2306 | &response); | ||
2307 | |||
2308 | // we should be able to us a gtk_dialog_run(), but it's | ||
2309 | // apparently not written to exist in a world without a higher | ||
2310 | // gtk_main(), so we manage its signal/destruction outselves. | ||
2311 | gtk_widget_show_all (win); | ||
2312 | gtk_main(); | ||
2313 | |||
2314 | //llinfos << "response: " << response << llendl; | ||
2315 | switch (response) | ||
2316 | { | ||
2317 | case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; | ||
2318 | case GTK_RESPONSE_YES: rtn = OSBTN_YES; break; | ||
2319 | case GTK_RESPONSE_NO: rtn = OSBTN_NO; break; | ||
2320 | case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break; | ||
2321 | case GTK_RESPONSE_NONE: | ||
2322 | case GTK_RESPONSE_CANCEL: | ||
2323 | case GTK_RESPONSE_CLOSE: | ||
2324 | case GTK_RESPONSE_DELETE_EVENT: | ||
2325 | default: rtn = OSBTN_CANCEL; | ||
2326 | } | ||
2327 | } | ||
2328 | else | ||
2329 | { | ||
2330 | fprintf(stderr, "MSGBOX: %s: %s\n", caption, text); | ||
2331 | llinfos << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << llendl; | ||
2332 | rtn = OSBTN_OK; | ||
2333 | } | ||
2334 | |||
2335 | if(gWindowImplementation != NULL) | ||
2336 | gWindowImplementation->afterDialog(); | ||
2337 | |||
2338 | return rtn; | ||
2339 | } | ||
2340 | |||
2341 | static void color_changed_callback(GtkWidget *widget, | ||
2342 | gpointer user_data) | ||
2343 | { | ||
2344 | GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); | ||
2345 | GdkColor *colorp = (GdkColor*)user_data; | ||
2346 | |||
2347 | gtk_color_selection_get_current_color(colorsel, colorp); | ||
2348 | } | ||
2349 | |||
2350 | BOOL LLWindowSDL::dialog_color_picker ( F32 *r, F32 *g, F32 *b) | ||
2351 | { | ||
2352 | BOOL rtn = FALSE; | ||
2353 | |||
2354 | beforeDialog(); | ||
2355 | |||
2356 | gtk_disable_setlocale(); | ||
2357 | if (gtk_init_check(NULL, NULL) | ||
2358 | // We can NOT expect to combine GTK and SDL's aggressive fullscreen | ||
2359 | && !was_fullscreen | ||
2360 | ) | ||
2361 | { | ||
2362 | GtkWidget *win = NULL; | ||
2363 | |||
2364 | win = gtk_color_selection_dialog_new(NULL); | ||
2365 | |||
2366 | # if LL_X11 | ||
2367 | // Get GTK to tell the window manager to associate this | ||
2368 | // dialog with our non-GTK SDL window, which should try | ||
2369 | // to keep it on top etc. | ||
2370 | if (SDL_XWindowID != None) | ||
2371 | { | ||
2372 | gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin | ||
2373 | GdkWindow *gdkwin = gdk_window_foreign_new(SDL_XWindowID); | ||
2374 | gdk_window_set_transient_for(GTK_WIDGET(win)->window, | ||
2375 | gdkwin); | ||
2376 | } | ||
2377 | # endif //LL_X11 | ||
2378 | |||
2379 | GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); | ||
2380 | |||
2381 | GdkColor color, orig_color; | ||
2382 | orig_color.red = guint16(65535 * *r); | ||
2383 | orig_color.green= guint16(65535 * *g); | ||
2384 | orig_color.blue = guint16(65535 * *b); | ||
2385 | color = orig_color; | ||
2386 | |||
2387 | gtk_color_selection_set_previous_color (colorsel, &color); | ||
2388 | gtk_color_selection_set_current_color (colorsel, &color); | ||
2389 | gtk_color_selection_set_has_palette (colorsel, TRUE); | ||
2390 | gtk_color_selection_set_has_opacity_control(colorsel, FALSE); | ||
2391 | |||
2392 | gint response = GTK_RESPONSE_NONE; | ||
2393 | g_signal_connect (win, | ||
2394 | "response", | ||
2395 | G_CALLBACK (response_callback), | ||
2396 | &response); | ||
2397 | |||
2398 | g_signal_connect (G_OBJECT (colorsel), "color_changed", | ||
2399 | G_CALLBACK (color_changed_callback), | ||
2400 | &color); | ||
2401 | |||
2402 | gtk_window_set_modal(GTK_WINDOW(win), TRUE); | ||
2403 | gtk_widget_show_all(win); | ||
2404 | // hide the help button - we don't service it. | ||
2405 | gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); | ||
2406 | gtk_main(); | ||
2407 | |||
2408 | if (response == GTK_RESPONSE_OK && | ||
2409 | (orig_color.red != color.red | ||
2410 | || orig_color.green != color.green | ||
2411 | || orig_color.blue != color.blue) ) | ||
2412 | { | ||
2413 | *r = color.red / 65535.0f; | ||
2414 | *g = color.green / 65535.0f; | ||
2415 | *b = color.blue / 65535.0f; | ||
2416 | rtn = TRUE; | ||
2417 | } | ||
2418 | } | ||
2419 | |||
2420 | afterDialog(); | ||
2421 | |||
2422 | return rtn; | ||
2423 | } | ||
2424 | #else | ||
2425 | S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type) | ||
2426 | { | ||
2427 | fprintf(stderr, "MSGBOX: %s: %s\n", caption, text); | ||
2428 | return 0; | ||
2429 | } | ||
2430 | |||
2431 | BOOL LLWindowSDL::dialog_color_picker ( F32 *r, F32 *g, F32 *b) | ||
2432 | { | ||
2433 | return (FALSE); | ||
2434 | } | ||
2435 | #endif // LL_GTK | ||
2436 | |||
2437 | // Open a URL with the user's default web browser. | ||
2438 | // Must begin with protocol identifier. | ||
2439 | void spawn_web_browser(const char* escaped_url) | ||
2440 | { | ||
2441 | llinfos << "spawn_web_browser: " << escaped_url << llendl; | ||
2442 | |||
2443 | #if LL_LINUX | ||
2444 | # if LL_X11 | ||
2445 | if (SDL_Display) // Just in case - before forking. | ||
2446 | XSync(SDL_Display, False); | ||
2447 | # endif // LL_X11 | ||
2448 | |||
2449 | std::string cmd; | ||
2450 | cmd = gDirUtilp->getAppRODataDir().c_str(); | ||
2451 | cmd += gDirUtilp->getDirDelimiter().c_str(); | ||
2452 | cmd += "launch_url.sh"; | ||
2453 | char* const argv[] = {(char*)cmd.c_str(), (char*)escaped_url, NULL}; | ||
2454 | |||
2455 | pid_t pid = fork(); | ||
2456 | if (pid == 0) | ||
2457 | { // child | ||
2458 | // disconnect from stdin/stdout/stderr, or child will | ||
2459 | // keep our output pipe undesirably alive if it outlives us. | ||
2460 | close(0); | ||
2461 | close(1); | ||
2462 | close(2); | ||
2463 | // end ourself by running the command | ||
2464 | execv(cmd.c_str(), argv); | ||
2465 | // if execv returns at all, there was a problem. | ||
2466 | llwarns << "execv failure when trying to start " << cmd << llendl; | ||
2467 | _exit(1); // _exit because we don't want atexit() clean-up! | ||
2468 | } else { | ||
2469 | if (pid > 0) | ||
2470 | { | ||
2471 | // parent - wait for child to die | ||
2472 | int childExitStatus; | ||
2473 | waitpid(pid, &childExitStatus, 0); | ||
2474 | } else { | ||
2475 | llwarns << "fork failure." << llendl; | ||
2476 | } | ||
2477 | } | ||
2478 | #endif // LL_LINUX | ||
2479 | |||
2480 | llinfos << "spawn_web_browser returning." << llendl; | ||
2481 | } | ||
2482 | |||
2483 | void shell_open( const char* file_path ) | ||
2484 | { | ||
2485 | // *FIX: (???) | ||
2486 | fprintf(stderr, "shell_open: %s\n", file_path); | ||
2487 | } | ||
2488 | |||
2489 | void *LLWindowSDL::getPlatformWindow() | ||
2490 | { | ||
2491 | #if LL_X11 | ||
2492 | // pointer to our static raw X window | ||
2493 | return (void*)&SDL_XWindowID; | ||
2494 | #else | ||
2495 | // doubt we really want to return a high-level SDL structure here. | ||
2496 | return NULL; | ||
2497 | #endif | ||
2498 | } | ||
2499 | |||
2500 | void LLWindowSDL::bringToFront() | ||
2501 | { | ||
2502 | // *FIX: (???) | ||
2503 | fprintf(stderr, "bringToFront\n"); | ||
2504 | } | ||
2505 | |||
2506 | #endif // LL_SDL | ||
diff --git a/linden/indra/llwindow/llwindowsdl.h b/linden/indra/llwindow/llwindowsdl.h new file mode 100644 index 0000000..0528b84 --- /dev/null +++ b/linden/indra/llwindow/llwindowsdl.h | |||
@@ -0,0 +1,217 @@ | |||
1 | /** | ||
2 | * @file llwindowsdl.h | ||
3 | * @brief SDL implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWSDL_H | ||
29 | #define LL_LLWINDOWSDL_H | ||
30 | |||
31 | // Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class | ||
32 | |||
33 | #include "llwindow.h" | ||
34 | |||
35 | #include "SDL/SDL.h" | ||
36 | |||
37 | #if LL_X11 | ||
38 | // get X11-specific headers for use in low-level stuff like copy-and-paste support | ||
39 | #include "SDL/SDL_syswm.h" | ||
40 | #endif | ||
41 | |||
42 | // AssertMacros.h does bad things. | ||
43 | #undef verify | ||
44 | #undef check | ||
45 | #undef require | ||
46 | |||
47 | |||
48 | class LLWindowSDL : public LLWindow | ||
49 | { | ||
50 | public: | ||
51 | /*virtual*/ void show(); | ||
52 | /*virtual*/ void hide(); | ||
53 | /*virtual*/ void close(); | ||
54 | /*virtual*/ BOOL getVisible(); | ||
55 | /*virtual*/ BOOL getMinimized(); | ||
56 | /*virtual*/ BOOL getMaximized(); | ||
57 | /*virtual*/ BOOL maximize(); | ||
58 | /*virtual*/ BOOL getFullscreen(); | ||
59 | /*virtual*/ BOOL getPosition(LLCoordScreen *position); | ||
60 | /*virtual*/ BOOL getSize(LLCoordScreen *size); | ||
61 | /*virtual*/ BOOL getSize(LLCoordWindow *size); | ||
62 | /*virtual*/ BOOL setPosition(LLCoordScreen position); | ||
63 | /*virtual*/ BOOL setSize(LLCoordScreen size); | ||
64 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync); | ||
65 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); | ||
66 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); | ||
67 | /*virtual*/ void showCursor(); | ||
68 | /*virtual*/ void hideCursor(); | ||
69 | /*virtual*/ void showCursorFromMouseMove(); | ||
70 | /*virtual*/ void hideCursorUntilMouseMove(); | ||
71 | /*virtual*/ BOOL isCursorHidden(); | ||
72 | /*virtual*/ void setCursor(ECursorType cursor); | ||
73 | /*virtual*/ ECursorType getCursor(); | ||
74 | /*virtual*/ void captureMouse(); | ||
75 | /*virtual*/ void releaseMouse(); | ||
76 | /*virtual*/ void setMouseClipping( BOOL b ); | ||
77 | /*virtual*/ BOOL isClipboardTextAvailable(); | ||
78 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); | ||
79 | /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); | ||
80 | /*virtual*/ void flashIcon(F32 seconds); | ||
81 | /*virtual*/ F32 getGamma(); | ||
82 | /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma | ||
83 | /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) | ||
84 | /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
85 | /*virtual*/ void gatherInput(); | ||
86 | /*virtual*/ void swapBuffers(); | ||
87 | |||
88 | /*virtual*/ LLString getTempFileName(); | ||
89 | /*virtual*/ void deleteFile( const char* file_name ); | ||
90 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ); | ||
91 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL); | ||
92 | |||
93 | /*virtual*/ void delayInputProcessing() { }; | ||
94 | |||
95 | // handy coordinate space conversion routines | ||
96 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); | ||
97 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); | ||
98 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); | ||
99 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); | ||
100 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); | ||
101 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); | ||
102 | |||
103 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); | ||
104 | /*virtual*/ F32 getNativeAspectRatio(); | ||
105 | /*virtual*/ F32 getPixelAspectRatio(); | ||
106 | /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } | ||
107 | |||
108 | /*virtual*/ void beforeDialog(); | ||
109 | /*virtual*/ void afterDialog(); | ||
110 | |||
111 | /*virtual*/ BOOL dialog_color_picker(F32 *r, F32 *g, F32 *b); | ||
112 | |||
113 | /*virtual*/ void *getPlatformWindow(); | ||
114 | /*virtual*/ void bringToFront(); | ||
115 | |||
116 | protected: | ||
117 | LLWindowSDL( | ||
118 | char *title, int x, int y, int width, int height, U32 flags, | ||
119 | BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, | ||
120 | BOOL ignore_pixel_depth); | ||
121 | ~LLWindowSDL(); | ||
122 | |||
123 | void initCursors(); | ||
124 | void quitCursors(); | ||
125 | BOOL isValid(); | ||
126 | void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); | ||
127 | |||
128 | |||
129 | // Changes display resolution. Returns true if successful | ||
130 | BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); | ||
131 | |||
132 | // Go back to last fullscreen display resolution. | ||
133 | BOOL setFullscreenResolution(); | ||
134 | |||
135 | void minimize(); | ||
136 | void restore(); | ||
137 | |||
138 | BOOL shouldPostQuit() { return mPostQuit; } | ||
139 | |||
140 | |||
141 | protected: | ||
142 | // | ||
143 | // Platform specific methods | ||
144 | // | ||
145 | |||
146 | // create or re-create the GL context/window. Called from the constructor and switchContext(). | ||
147 | BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); | ||
148 | void destroyContext(); | ||
149 | void setupFailure(const char* text, const char* caption, U32 type); | ||
150 | void adjustCursorDecouple(bool warpingMouse = false); | ||
151 | void fixWindowSize(void); | ||
152 | U32 SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain); | ||
153 | BOOL SDLReallyCaptureInput(BOOL capture); | ||
154 | |||
155 | // | ||
156 | // Platform specific variables | ||
157 | // | ||
158 | U32 mGrabbyKeyFlags; | ||
159 | int mReallyCapturedCount; | ||
160 | SDL_Surface * mWindow; | ||
161 | char * mWindowTitle; | ||
162 | double mOriginalAspectRatio; | ||
163 | BOOL mCursorDecoupled; | ||
164 | S32 mCursorLastEventDeltaX; | ||
165 | S32 mCursorLastEventDeltaY; | ||
166 | BOOL mCursorIgnoreNextDelta; | ||
167 | BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. | ||
168 | LLCoordScreen mNeedsResizeSize; | ||
169 | F32 mOverrideAspectRatio; | ||
170 | F32 mGamma; | ||
171 | |||
172 | int mSDLFlags; | ||
173 | |||
174 | SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; | ||
175 | int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ | ||
176 | int mIsMinimized; /* 0=no, 1=yes, else unknown */ | ||
177 | |||
178 | friend class LLWindowManager; | ||
179 | |||
180 | #if LL_X11 | ||
181 | private: | ||
182 | // These are set up by the X11 clipboard initialization code | ||
183 | Window mSDL_XWindowID; | ||
184 | void (*Lock_Display)(void); | ||
185 | void (*Unlock_Display)(void); | ||
186 | // more X11 clipboard stuff | ||
187 | int init_x11clipboard(void); | ||
188 | void quit_x11clipboard(void); | ||
189 | int is_empty_x11clipboard(void); | ||
190 | void put_x11clipboard(int type, int srclen, const char *src); | ||
191 | void get_x11clipboard(int type, int *dstlen, char **dst); | ||
192 | void x11_set_urgent(BOOL urgent); | ||
193 | BOOL mFlashing; | ||
194 | LLTimer mFlashTimer; | ||
195 | #endif //LL_X11 | ||
196 | |||
197 | |||
198 | }; | ||
199 | |||
200 | |||
201 | class LLSplashScreenSDL : public LLSplashScreen | ||
202 | { | ||
203 | public: | ||
204 | LLSplashScreenSDL(); | ||
205 | virtual ~LLSplashScreenSDL(); | ||
206 | |||
207 | /*virtual*/ void showImpl(); | ||
208 | /*virtual*/ void updateImpl(const char* mesg); | ||
209 | /*virtual*/ void hideImpl(); | ||
210 | }; | ||
211 | |||
212 | S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type); | ||
213 | |||
214 | void load_url_external(const char* url); | ||
215 | void shell_open( const char* file_path ); | ||
216 | |||
217 | #endif //LL_LLWINDOWSDL_H | ||
diff --git a/linden/indra/llwindow/llwindowwin32.cpp b/linden/indra/llwindow/llwindowwin32.cpp new file mode 100644 index 0000000..b405bdb --- /dev/null +++ b/linden/indra/llwindow/llwindowwin32.cpp | |||
@@ -0,0 +1,3255 @@ | |||
1 | /** | ||
2 | * @file llwindowwin32.cpp | ||
3 | * @brief Platform-dependent implementation of llwindow | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #if LL_WINDOWS && !LL_MESA_HEADLESS | ||
31 | |||
32 | #include "llwindowwin32.h" | ||
33 | |||
34 | #include <commdlg.h> | ||
35 | #include <WinUser.h> | ||
36 | #include <mapi.h> | ||
37 | #include <process.h> // for _spawn | ||
38 | #include <shellapi.h> | ||
39 | |||
40 | // Require DirectInput version 8 | ||
41 | #define DIRECTINPUT_VERSION 0x0800 | ||
42 | #include <dinput.h> | ||
43 | |||
44 | |||
45 | #include "llkeyboardwin32.h" | ||
46 | #include "llerror.h" | ||
47 | #include "llgl.h" | ||
48 | #include "llstring.h" | ||
49 | #include "lldir.h" | ||
50 | |||
51 | #include "llglheaders.h" | ||
52 | |||
53 | #include "indra_constants.h" | ||
54 | |||
55 | // culled from winuser.h | ||
56 | const S32 WM_MOUSEWHEEL = 0x020A; | ||
57 | const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */ | ||
58 | const S32 MAX_MESSAGE_PER_UPDATE = 20; | ||
59 | const S32 BITS_PER_PIXEL = 32; | ||
60 | const S32 MAX_NUM_RESOLUTIONS = 32; | ||
61 | const F32 ICON_FLASH_TIME = 0.5f; | ||
62 | |||
63 | extern BOOL gDebugWindowProc; | ||
64 | |||
65 | LPWSTR gIconResource = IDI_APPLICATION; | ||
66 | |||
67 | LLW32MsgCallback gAsyncMsgCallback = NULL; | ||
68 | |||
69 | // | ||
70 | // LLWindowWin32 | ||
71 | // | ||
72 | |||
73 | void show_window_creation_error(const char* title) | ||
74 | { | ||
75 | llwarns << title << llendl; | ||
76 | shell_open( "help/window_creation_error.html"); | ||
77 | /* | ||
78 | OSMessageBox( | ||
79 | "Second Life is unable to run because it can't set up your display.\n" | ||
80 | "We need to be able to make a 32-bit color window at 1024x768, with\n" | ||
81 | "an 8 bit alpha channel.\n" | ||
82 | "\n" | ||
83 | "First, be sure your monitor is set to True Color (32-bit) in\n" | ||
84 | "Start -> Control Panels -> Display -> Settings.\n" | ||
85 | "\n" | ||
86 | "Otherwise, this may be due to video card driver issues.\n" | ||
87 | "Please make sure you have the latest video card drivers installed.\n" | ||
88 | "ATI drivers are available at http://www.ati.com/\n" | ||
89 | "nVidia drivers are available at http://www.nvidia.com/\n" | ||
90 | "\n" | ||
91 | "If you continue to receive this message, contact customer service.", | ||
92 | title, | ||
93 | OSMB_OK); | ||
94 | */ | ||
95 | } | ||
96 | |||
97 | BOOL check_for_card(const char* RENDERER, const char* bad_card) | ||
98 | { | ||
99 | if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) | ||
100 | { | ||
101 | char buffer[1024]; | ||
102 | sprintf(buffer, | ||
103 | "Your video card appears to be a %s, which Second Life does not support.\n" | ||
104 | "\n" | ||
105 | "Second Life requires a video card with 32 Mb of memory or more, as well as\n" | ||
106 | "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" | ||
107 | "and ATI Radeon 8500 or better.\n" | ||
108 | "\n" | ||
109 | "If you own a supported card and continue to receive this message, try \n" | ||
110 | "updating to the latest video card drivers. Otherwise look in the\n" | ||
111 | "secondlife.com support section or e-mail technical support\n" | ||
112 | "\n" | ||
113 | "You can try to run Second Life, but it will probably crash or run\n" | ||
114 | "very slowly. Try anyway?", | ||
115 | bad_card); | ||
116 | S32 button = OSMessageBox(buffer, "Unsupported video card", OSMB_YESNO); | ||
117 | if (OSBTN_YES == button) | ||
118 | { | ||
119 | return FALSE; | ||
120 | } | ||
121 | else | ||
122 | { | ||
123 | return TRUE; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | return FALSE; | ||
128 | } | ||
129 | |||
130 | //static | ||
131 | BOOL LLWindowWin32::sIsClassRegistered = FALSE; | ||
132 | |||
133 | |||
134 | |||
135 | LPDIRECTINPUT8 g_pDI = NULL; | ||
136 | LPDIRECTINPUTDEVICE8 g_pJoystick = NULL; | ||
137 | BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, | ||
138 | VOID* pContext ); | ||
139 | BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, | ||
140 | VOID* pContext ); | ||
141 | |||
142 | |||
143 | LLWindowWin32::LLWindowWin32(char *title, char *name, S32 x, S32 y, S32 width, | ||
144 | S32 height, U32 flags, | ||
145 | BOOL fullscreen, BOOL clearBg, | ||
146 | BOOL disable_vsync, BOOL use_gl, | ||
147 | BOOL ignore_pixel_depth) | ||
148 | : LLWindow(fullscreen, flags) | ||
149 | { | ||
150 | mIconResource = gIconResource; | ||
151 | mOverrideAspectRatio = 0.f; | ||
152 | mNativeAspectRatio = 0.f; | ||
153 | mMousePositionModified = FALSE; | ||
154 | mInputProcessingPaused = FALSE; | ||
155 | |||
156 | // Initialize the keyboard | ||
157 | gKeyboard = new LLKeyboardWin32(); | ||
158 | |||
159 | GLuint pixel_format; | ||
160 | WNDCLASS wc; | ||
161 | DWORD dw_ex_style; | ||
162 | DWORD dw_style; | ||
163 | RECT window_rect; | ||
164 | |||
165 | // Set the window title | ||
166 | if (!title) | ||
167 | { | ||
168 | mWindowTitle = new WCHAR[50]; | ||
169 | wsprintf(mWindowTitle, L"OpenGL Window"); | ||
170 | } | ||
171 | else | ||
172 | { | ||
173 | mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. | ||
174 | mbstowcs(mWindowTitle, title, 255); | ||
175 | mWindowTitle[255] = 0; | ||
176 | } | ||
177 | |||
178 | // Set the window class name | ||
179 | if (!name) | ||
180 | { | ||
181 | mWindowClassName = new WCHAR[50]; | ||
182 | wsprintf(mWindowClassName, L"OpenGL Window"); | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. | ||
187 | mbstowcs(mWindowClassName, name, 255); | ||
188 | mWindowClassName[255] = 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | // We're not clipping yet | ||
193 | SetRect( &mOldMouseClip, 0, 0, 0, 0 ); | ||
194 | |||
195 | // Make an instance of our window then define the window class | ||
196 | mhInstance = GetModuleHandle(NULL); | ||
197 | mWndProc = NULL; | ||
198 | |||
199 | mSwapMethod = SWAP_METHOD_UNDEFINED; | ||
200 | |||
201 | // No WPARAM yet. | ||
202 | mLastSizeWParam = 0; | ||
203 | |||
204 | // Windows GDI rects don't include rightmost pixel | ||
205 | window_rect.left = (long) 0; | ||
206 | window_rect.right = (long) width; | ||
207 | window_rect.top = (long) 0; | ||
208 | window_rect.bottom = (long) height; | ||
209 | |||
210 | // Grab screen size to sanitize the window | ||
211 | S32 window_border_y = GetSystemMetrics(SM_CYBORDER); | ||
212 | S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); | ||
213 | S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); | ||
214 | S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); | ||
215 | S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); | ||
216 | |||
217 | if (x < virtual_screen_x) x = virtual_screen_x; | ||
218 | if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; | ||
219 | |||
220 | if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; | ||
221 | if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; | ||
222 | |||
223 | if (!sIsClassRegistered) | ||
224 | { | ||
225 | // Force redraw when resized and create a private device context | ||
226 | |||
227 | // Makes double click messages. | ||
228 | wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; | ||
229 | |||
230 | // Set message handler function | ||
231 | wc.lpfnWndProc = (WNDPROC) mainWindowProc; | ||
232 | |||
233 | // unused | ||
234 | wc.cbClsExtra = 0; | ||
235 | wc.cbWndExtra = 0; | ||
236 | |||
237 | wc.hInstance = mhInstance; | ||
238 | wc.hIcon = LoadIcon(mhInstance, mIconResource); | ||
239 | |||
240 | // We will set the cursor ourselves | ||
241 | wc.hCursor = NULL; | ||
242 | |||
243 | // background color is not used | ||
244 | if (clearBg) | ||
245 | { | ||
246 | wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); | ||
247 | } | ||
248 | else | ||
249 | { | ||
250 | wc.hbrBackground = (HBRUSH) NULL; | ||
251 | } | ||
252 | |||
253 | // we don't use windows menus | ||
254 | wc.lpszMenuName = NULL; | ||
255 | |||
256 | wc.lpszClassName = mWindowClassName; | ||
257 | |||
258 | if (!RegisterClass(&wc)) | ||
259 | { | ||
260 | OSMessageBox("RegisterClass failed", "Error", OSMB_OK); | ||
261 | return; | ||
262 | } | ||
263 | sIsClassRegistered = TRUE; | ||
264 | } | ||
265 | |||
266 | //----------------------------------------------------------------------- | ||
267 | // Get the current refresh rate | ||
268 | //----------------------------------------------------------------------- | ||
269 | |||
270 | DEVMODE dev_mode; | ||
271 | DWORD current_refresh; | ||
272 | if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) | ||
273 | { | ||
274 | current_refresh = dev_mode.dmDisplayFrequency; | ||
275 | mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | current_refresh = 60; | ||
280 | } | ||
281 | |||
282 | //----------------------------------------------------------------------- | ||
283 | // Drop resolution and go fullscreen | ||
284 | // use a display mode with our desired size and depth, with a refresh | ||
285 | // rate as close at possible to the users' default | ||
286 | //----------------------------------------------------------------------- | ||
287 | if (mFullscreen) | ||
288 | { | ||
289 | BOOL success = FALSE; | ||
290 | DWORD closest_refresh = 0; | ||
291 | |||
292 | for (S32 mode_num = 0;; mode_num++) | ||
293 | { | ||
294 | if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) | ||
295 | { | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | if (dev_mode.dmPelsWidth == width && | ||
300 | dev_mode.dmPelsHeight == height && | ||
301 | dev_mode.dmBitsPerPel == BITS_PER_PIXEL) | ||
302 | { | ||
303 | success = TRUE; | ||
304 | if ((dev_mode.dmDisplayFrequency - current_refresh) | ||
305 | < (closest_refresh - current_refresh)) | ||
306 | { | ||
307 | closest_refresh = dev_mode.dmDisplayFrequency; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | if (closest_refresh == 0) | ||
313 | { | ||
314 | llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl; | ||
315 | success = FALSE; | ||
316 | } | ||
317 | |||
318 | // If we found a good resolution, use it. | ||
319 | if (success) | ||
320 | { | ||
321 | success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); | ||
322 | } | ||
323 | |||
324 | // Keep a copy of the actual current device mode in case we minimize | ||
325 | // and change the screen resolution. JC | ||
326 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); | ||
327 | |||
328 | // If it failed, we don't want to run fullscreen | ||
329 | if (success) | ||
330 | { | ||
331 | mFullscreen = TRUE; | ||
332 | mFullscreenWidth = dev_mode.dmPelsWidth; | ||
333 | mFullscreenHeight = dev_mode.dmPelsHeight; | ||
334 | mFullscreenBits = dev_mode.dmBitsPerPel; | ||
335 | mFullscreenRefresh = dev_mode.dmDisplayFrequency; | ||
336 | |||
337 | llinfos << "Running at " << dev_mode.dmPelsWidth | ||
338 | << "x" << dev_mode.dmPelsHeight | ||
339 | << "x" << dev_mode.dmBitsPerPel | ||
340 | << " @ " << dev_mode.dmDisplayFrequency | ||
341 | << llendl; | ||
342 | } | ||
343 | else | ||
344 | { | ||
345 | mFullscreen = FALSE; | ||
346 | mFullscreenWidth = -1; | ||
347 | mFullscreenHeight = -1; | ||
348 | mFullscreenBits = -1; | ||
349 | mFullscreenRefresh = -1; | ||
350 | |||
351 | char error[256]; | ||
352 | sprintf(error, "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); | ||
353 | OSMessageBox(error, "Error", OSMB_OK); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | //----------------------------------------------------------------------- | ||
358 | // Resize window to account for borders | ||
359 | //----------------------------------------------------------------------- | ||
360 | if (mFullscreen) | ||
361 | { | ||
362 | dw_ex_style = WS_EX_APPWINDOW; | ||
363 | dw_style = WS_POPUP; | ||
364 | |||
365 | // Move window borders out not to cover window contents | ||
366 | AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); | ||
367 | } | ||
368 | else | ||
369 | { | ||
370 | // Window with an edge | ||
371 | dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; | ||
372 | dw_style = WS_OVERLAPPEDWINDOW; | ||
373 | } | ||
374 | |||
375 | //----------------------------------------------------------------------- | ||
376 | // Create the window | ||
377 | // Microsoft help indicates that GL windows must be created with | ||
378 | // WS_CLIPSIBLINGS and WS_CLIPCHILDREN, but not CS_PARENTDC | ||
379 | //----------------------------------------------------------------------- | ||
380 | mWindowHandle = CreateWindowEx(dw_ex_style, | ||
381 | mWindowClassName, | ||
382 | mWindowTitle, | ||
383 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, | ||
384 | x, // x pos | ||
385 | y, // y pos | ||
386 | window_rect.right - window_rect.left, // width | ||
387 | window_rect.bottom - window_rect.top, // height | ||
388 | NULL, | ||
389 | NULL, | ||
390 | mhInstance, | ||
391 | NULL); | ||
392 | |||
393 | if (!mWindowHandle) | ||
394 | { | ||
395 | DestroyWindow(mWindowHandle); | ||
396 | OSMessageBox("Window creation error", "Error", OSMB_OK); | ||
397 | return; | ||
398 | } | ||
399 | |||
400 | // TODO: add this after resolving _WIN32_WINNT issue | ||
401 | // if (!fullscreen) | ||
402 | // { | ||
403 | // TRACKMOUSEEVENT track_mouse_event; | ||
404 | // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); | ||
405 | // track_mouse_event.dwFlags = TME_LEAVE; | ||
406 | // track_mouse_event.hwndTrack = mWindowHandle; | ||
407 | // track_mouse_event.dwHoverTime = HOVER_DEFAULT; | ||
408 | // TrackMouseEvent( &track_mouse_event ); | ||
409 | // } | ||
410 | |||
411 | |||
412 | |||
413 | S32 pfdflags = PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER; | ||
414 | if (use_gl) | ||
415 | { | ||
416 | pfdflags |= PFD_SUPPORT_OPENGL; | ||
417 | } | ||
418 | |||
419 | //----------------------------------------------------------------------- | ||
420 | // Create GL drawing context | ||
421 | //----------------------------------------------------------------------- | ||
422 | PIXELFORMATDESCRIPTOR pfd = | ||
423 | { | ||
424 | sizeof(PIXELFORMATDESCRIPTOR), | ||
425 | 1, | ||
426 | pfdflags, | ||
427 | PFD_TYPE_RGBA, | ||
428 | BITS_PER_PIXEL, | ||
429 | 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused | ||
430 | 8, // alpha bits | ||
431 | 0, // alpha shift | ||
432 | 0, // accum bits | ||
433 | 0, 0, 0, 0, // accum RGBA | ||
434 | 24, // depth bits | ||
435 | 8, // stencil bits, avi added for stencil test | ||
436 | 0, | ||
437 | PFD_MAIN_PLANE, | ||
438 | 0, | ||
439 | 0, 0, 0 | ||
440 | }; | ||
441 | |||
442 | if (!(mhDC = GetDC(mWindowHandle))) | ||
443 | { | ||
444 | close(); | ||
445 | OSMessageBox("Can't make GL device context", "Error", OSMB_OK); | ||
446 | return; | ||
447 | } | ||
448 | |||
449 | if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) | ||
450 | { | ||
451 | close(); | ||
452 | OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK); | ||
453 | return; | ||
454 | } | ||
455 | |||
456 | // Verify what pixel format we actually received. | ||
457 | if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), | ||
458 | &pfd)) | ||
459 | { | ||
460 | close(); | ||
461 | OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | // sanity check pfd returned by Windows | ||
466 | if (!ignore_pixel_depth && (pfd.cColorBits < 32)) | ||
467 | { | ||
468 | close(); | ||
469 | OSMessageBox( | ||
470 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
471 | "Please go to Control Panels -> Display -> Settings and\n" | ||
472 | "set the screen to 32-bit color.\n" | ||
473 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
474 | "will automatically adjust the screen each time it runs.", | ||
475 | "Error", | ||
476 | OSMB_OK); | ||
477 | return; | ||
478 | } | ||
479 | |||
480 | if (!ignore_pixel_depth && (pfd.cAlphaBits < 8)) | ||
481 | { | ||
482 | close(); | ||
483 | OSMessageBox( | ||
484 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
485 | "channel. Usually this is due to video card driver issues.\n" | ||
486 | "Please make sure you have the latest video card drivers installed.\n" | ||
487 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
488 | "Control Panels -> Display -> Settings.\n" | ||
489 | "If you continue to receive this message, contact customer service.", | ||
490 | "Error", | ||
491 | OSMB_OK); | ||
492 | return; | ||
493 | } | ||
494 | |||
495 | if (!SetPixelFormat(mhDC, pixel_format, &pfd)) | ||
496 | { | ||
497 | close(); | ||
498 | OSMessageBox("Can't set pixel format", "Error", OSMB_OK); | ||
499 | return; | ||
500 | } | ||
501 | |||
502 | if (use_gl) | ||
503 | { | ||
504 | if (!(mhRC = wglCreateContext(mhDC))) | ||
505 | { | ||
506 | close(); | ||
507 | OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); | ||
508 | return; | ||
509 | } | ||
510 | |||
511 | if (!wglMakeCurrent(mhDC, mhRC)) | ||
512 | { | ||
513 | close(); | ||
514 | OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | // Check for some explicitly unsupported cards. | ||
519 | const char* RENDERER = (const char*) glGetString(GL_RENDERER); | ||
520 | |||
521 | const char* CARD_LIST[] = | ||
522 | { "RAGE 128", | ||
523 | "RIVA TNT2", | ||
524 | "Intel 810", | ||
525 | "3Dfx/Voodoo3", | ||
526 | "Radeon 7000", | ||
527 | "Radeon 7200", | ||
528 | "Radeon 7500", | ||
529 | "Radeon DDR", | ||
530 | "Radeon VE", | ||
531 | "GDI Generic" }; | ||
532 | const S32 CARD_COUNT = sizeof(CARD_LIST)/sizeof(char*); | ||
533 | |||
534 | // Future candidates: | ||
535 | // ProSavage/Twister | ||
536 | // SuperSavage | ||
537 | |||
538 | S32 i; | ||
539 | for (i = 0; i < CARD_COUNT; i++) | ||
540 | { | ||
541 | if (check_for_card(RENDERER, CARD_LIST[i])) | ||
542 | { | ||
543 | close(); | ||
544 | shell_open( "help/unsupported_card.html" ); | ||
545 | return; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | gGLManager.initWGL(); | ||
550 | |||
551 | if (gGLManager.mHasWGLARBPixelFormat && (wglChoosePixelFormatARB != NULL)) | ||
552 | { | ||
553 | // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we | ||
554 | // can get exactly what we want. | ||
555 | GLint attrib_list[256]; | ||
556 | S32 cur_attrib = 0; | ||
557 | |||
558 | attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; | ||
559 | attrib_list[cur_attrib++] = 24; | ||
560 | |||
561 | attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; | ||
562 | attrib_list[cur_attrib++] = 8; | ||
563 | |||
564 | attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; | ||
565 | attrib_list[cur_attrib++] = GL_TRUE; | ||
566 | |||
567 | attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; | ||
568 | attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; | ||
569 | |||
570 | attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; | ||
571 | attrib_list[cur_attrib++] = GL_TRUE; | ||
572 | |||
573 | attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; | ||
574 | attrib_list[cur_attrib++] = GL_TRUE; | ||
575 | |||
576 | attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; | ||
577 | attrib_list[cur_attrib++] = 24; | ||
578 | |||
579 | attrib_list[cur_attrib++] = WGL_RED_BITS_ARB; | ||
580 | attrib_list[cur_attrib++] = 8; | ||
581 | |||
582 | attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB; | ||
583 | attrib_list[cur_attrib++] = 8; | ||
584 | |||
585 | attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB; | ||
586 | attrib_list[cur_attrib++] = 8; | ||
587 | |||
588 | attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; | ||
589 | attrib_list[cur_attrib++] = 8; | ||
590 | |||
591 | // End the list | ||
592 | attrib_list[cur_attrib++] = 0; | ||
593 | |||
594 | GLint pixel_formats[256]; | ||
595 | U32 num_formats = 0; | ||
596 | |||
597 | // First we try and get a 32 bit depth pixel format | ||
598 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
599 | if (!result) | ||
600 | { | ||
601 | close(); | ||
602 | show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); | ||
603 | return; | ||
604 | } | ||
605 | |||
606 | if (!num_formats) | ||
607 | { | ||
608 | llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl; | ||
609 | // Try 24-bit format | ||
610 | attrib_list[1] = 24; | ||
611 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
612 | if (!result) | ||
613 | { | ||
614 | close(); | ||
615 | show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); | ||
616 | return; | ||
617 | } | ||
618 | |||
619 | if (!num_formats) | ||
620 | { | ||
621 | llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl; | ||
622 | attrib_list[1] = 16; | ||
623 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
624 | if (!result || !num_formats) | ||
625 | { | ||
626 | close(); | ||
627 | show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); | ||
628 | return; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl; | ||
633 | |||
634 | pixel_format = pixel_formats[0]; | ||
635 | } | ||
636 | |||
637 | DestroyWindow(mWindowHandle); | ||
638 | |||
639 | mWindowHandle = CreateWindowEx(dw_ex_style, | ||
640 | mWindowClassName, | ||
641 | mWindowTitle, | ||
642 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, | ||
643 | x, // x pos | ||
644 | y, // y pos | ||
645 | window_rect.right - window_rect.left, // width | ||
646 | window_rect.bottom - window_rect.top, // height | ||
647 | NULL, | ||
648 | NULL, | ||
649 | mhInstance, | ||
650 | NULL); | ||
651 | |||
652 | if (!(mhDC = GetDC(mWindowHandle))) | ||
653 | { | ||
654 | close(); | ||
655 | OSMessageBox("Can't make GL device context", "Error", OSMB_OK); | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | if (!SetPixelFormat(mhDC, pixel_format, &pfd)) | ||
660 | { | ||
661 | close(); | ||
662 | OSMessageBox("Can't set pixel format", "Error", OSMB_OK); | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | int swap_method = 0; | ||
667 | GLint swap_query = WGL_SWAP_METHOD_ARB; | ||
668 | |||
669 | if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) | ||
670 | { | ||
671 | switch (swap_method) | ||
672 | { | ||
673 | case WGL_SWAP_EXCHANGE_ARB: | ||
674 | mSwapMethod = SWAP_METHOD_EXCHANGE; | ||
675 | llinfos << "Swap Method: Exchange" << llendl; | ||
676 | break; | ||
677 | case WGL_SWAP_COPY_ARB: | ||
678 | mSwapMethod = SWAP_METHOD_COPY; | ||
679 | llinfos << "Swap Method: Copy" << llendl; | ||
680 | break; | ||
681 | case WGL_SWAP_UNDEFINED_ARB: | ||
682 | mSwapMethod = SWAP_METHOD_UNDEFINED; | ||
683 | llinfos << "Swap Method: Undefined" << llendl; | ||
684 | break; | ||
685 | default: | ||
686 | mSwapMethod = SWAP_METHOD_UNDEFINED; | ||
687 | llinfos << "Swap Method: Unknown" << llendl; | ||
688 | break; | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | else | ||
693 | { | ||
694 | llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl; | ||
695 | } | ||
696 | |||
697 | // Verify what pixel format we actually received. | ||
698 | if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), | ||
699 | &pfd)) | ||
700 | { | ||
701 | close(); | ||
702 | OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); | ||
703 | return; | ||
704 | } | ||
705 | llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) | ||
706 | << " Alpha Bits " << S32(pfd.cAlphaBits) | ||
707 | << " Depth Bits " << S32(pfd.cDepthBits) | ||
708 | << llendl; | ||
709 | |||
710 | if (pfd.cColorBits < 32) | ||
711 | { | ||
712 | close(); | ||
713 | OSMessageBox( | ||
714 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
715 | "Please go to Control Panels -> Display -> Settings and\n" | ||
716 | "set the screen to 32-bit color.\n" | ||
717 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
718 | "will automatically adjust the screen each time it runs.", | ||
719 | "Error", | ||
720 | OSMB_OK); | ||
721 | return; | ||
722 | } | ||
723 | |||
724 | if (pfd.cAlphaBits < 8) | ||
725 | { | ||
726 | close(); | ||
727 | OSMessageBox( | ||
728 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
729 | "channel. Usually this is due to video card driver issues.\n" | ||
730 | "Please make sure you have the latest video card drivers installed.\n" | ||
731 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
732 | "Control Panels -> Display -> Settings.\n" | ||
733 | "If you continue to receive this message, contact customer service.", | ||
734 | "Error", | ||
735 | OSMB_OK); | ||
736 | return; | ||
737 | } | ||
738 | |||
739 | if (!(mhRC = wglCreateContext(mhDC))) | ||
740 | { | ||
741 | close(); | ||
742 | OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | if (!wglMakeCurrent(mhDC, mhRC)) | ||
747 | { | ||
748 | close(); | ||
749 | OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); | ||
750 | return; | ||
751 | } | ||
752 | |||
753 | if (!gGLManager.initGL()) | ||
754 | { | ||
755 | close(); | ||
756 | OSMessageBox( | ||
757 | "Second Life is unable to run because your video card drivers\n" | ||
758 | "are out of date or unsupported. Please make sure you have\n" | ||
759 | "the latest video card drivers installed.\n\n" | ||
760 | "If you continue to receive this message, contact customer service.", | ||
761 | "Error", | ||
762 | OSMB_OK); | ||
763 | return; | ||
764 | } | ||
765 | |||
766 | // Disable vertical sync for swap | ||
767 | if (disable_vsync && wglSwapIntervalEXT) | ||
768 | { | ||
769 | llinfos << "Disabling vertical sync" << llendl; | ||
770 | wglSwapIntervalEXT(0); | ||
771 | } | ||
772 | else | ||
773 | { | ||
774 | llinfos << "Keeping vertical sync" << llendl; | ||
775 | } | ||
776 | |||
777 | |||
778 | // OK, let's get the current gamma information and store it off. | ||
779 | mCurrentGamma = 0.f; // Not set, default; | ||
780 | if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp)) | ||
781 | { | ||
782 | llwarns << "Unable to get device gamma ramp" << llendl; | ||
783 | } | ||
784 | |||
785 | // Calculate what the current gamma is. From a posting by Garrett T. Bass, Get/SetDeviceGammaRamp Demystified | ||
786 | // http://apollo.iwt.uni-bielefeld.de/~ml_robot/OpenGL-04-2000/0058.html | ||
787 | |||
788 | // We're going to assume that gamma's the same for all 3 channels, because I don't feel like doing it otherwise. | ||
789 | // Using the red channel. | ||
790 | |||
791 | F32 Csum = 0.0; | ||
792 | S32 Ccount = 0; | ||
793 | for (i = 0; i < 256; i++) | ||
794 | { | ||
795 | if (i != 0 && mPrevGammaRamp[i] != 0 && mPrevGammaRamp[i] != 65536) | ||
796 | { | ||
797 | F64 B = (i % 256) / 256.0; | ||
798 | F64 A = mPrevGammaRamp[i] / 65536.0; | ||
799 | F32 C = (F32) ( log(A) / log(B) ); | ||
800 | Csum += C; | ||
801 | Ccount++; | ||
802 | } | ||
803 | } | ||
804 | mCurrentGamma = Csum / Ccount; | ||
805 | |||
806 | llinfos << "Previous gamma: " << mCurrentGamma << llendl; | ||
807 | } | ||
808 | |||
809 | |||
810 | //store this pointer for wndProc callback | ||
811 | SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); | ||
812 | |||
813 | //start with arrow cursor | ||
814 | initCursors(); | ||
815 | setCursor( UI_CURSOR_ARROW ); | ||
816 | |||
817 | // Direct Input | ||
818 | HRESULT hr; | ||
819 | |||
820 | if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, | ||
821 | IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) ) | ||
822 | { | ||
823 | llwarns << "Direct8InputCreate failed!" << llendl; | ||
824 | } | ||
825 | else | ||
826 | { | ||
827 | while(1) | ||
828 | { | ||
829 | // Look for a simple joystick we can use for this sample program. | ||
830 | if (FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, | ||
831 | EnumJoysticksCallback, | ||
832 | NULL, DIEDFL_ATTACHEDONLY ) ) ) | ||
833 | break; | ||
834 | if (!g_pJoystick) | ||
835 | break; | ||
836 | if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick ) ) ) | ||
837 | break; | ||
838 | if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, | ||
839 | (VOID*)mWindowHandle, DIDFT_ALL ) ) ) | ||
840 | break; | ||
841 | g_pJoystick->Acquire(); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | |||
846 | SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer | ||
847 | mJoyStickState = 0; | ||
848 | mJoyButtonState = 0; | ||
849 | } | ||
850 | |||
851 | |||
852 | LLWindowWin32::~LLWindowWin32() | ||
853 | { | ||
854 | delete [] mWindowTitle; | ||
855 | mWindowTitle = NULL; | ||
856 | |||
857 | delete [] mSupportedResolutions; | ||
858 | mSupportedResolutions = NULL; | ||
859 | |||
860 | delete mWindowClassName; | ||
861 | mWindowClassName = NULL; | ||
862 | } | ||
863 | |||
864 | void LLWindowWin32::show() | ||
865 | { | ||
866 | ShowWindow(mWindowHandle, SW_SHOW); | ||
867 | SetForegroundWindow(mWindowHandle); | ||
868 | SetFocus(mWindowHandle); | ||
869 | } | ||
870 | |||
871 | void LLWindowWin32::hide() | ||
872 | { | ||
873 | setMouseClipping(FALSE); | ||
874 | ShowWindow(mWindowHandle, SW_HIDE); | ||
875 | } | ||
876 | |||
877 | void LLWindowWin32::minimize() | ||
878 | { | ||
879 | setMouseClipping(FALSE); | ||
880 | showCursor(); | ||
881 | ShowWindow(mWindowHandle, SW_MINIMIZE); | ||
882 | } | ||
883 | |||
884 | |||
885 | void LLWindowWin32::restore() | ||
886 | { | ||
887 | ShowWindow(mWindowHandle, SW_RESTORE); | ||
888 | SetForegroundWindow(mWindowHandle); | ||
889 | SetFocus(mWindowHandle); | ||
890 | } | ||
891 | |||
892 | |||
893 | // close() destroys all OS-specific code associated with a window. | ||
894 | // Usually called from LLWindowManager::destroyWindow() | ||
895 | void LLWindowWin32::close() | ||
896 | { | ||
897 | llinfos << "Closing LLWindowWin32" << llendl; | ||
898 | // Is window is already closed? | ||
899 | if (!mWindowHandle) | ||
900 | { | ||
901 | return; | ||
902 | } | ||
903 | |||
904 | // Make sure cursor is visible and we haven't mangled the clipping state. | ||
905 | setMouseClipping(FALSE); | ||
906 | showCursor(); | ||
907 | |||
908 | // Go back to screen mode written in the registry. | ||
909 | if (mFullscreen) | ||
910 | { | ||
911 | resetDisplayResolution(); | ||
912 | } | ||
913 | |||
914 | // Clean up remaining GL state | ||
915 | llinfos << "Shutting down GL" << llendl; | ||
916 | gGLManager.shutdownGL(); | ||
917 | |||
918 | llinfos << "Releasing Context" << llendl; | ||
919 | if (mhRC) | ||
920 | { | ||
921 | if (!wglMakeCurrent(NULL, NULL)) | ||
922 | { | ||
923 | llwarns << "Release of DC and RC failed" << llendl; | ||
924 | } | ||
925 | |||
926 | if (!wglDeleteContext(mhRC)) | ||
927 | { | ||
928 | llwarns << "Release of rendering context failed" << llendl; | ||
929 | } | ||
930 | |||
931 | mhRC = NULL; | ||
932 | } | ||
933 | |||
934 | // Restore gamma to the system values. | ||
935 | restoreGamma(); | ||
936 | |||
937 | if (mhDC && !ReleaseDC(mWindowHandle, mhDC)) | ||
938 | { | ||
939 | llwarns << "Release of ghDC failed" << llendl; | ||
940 | mhDC = NULL; | ||
941 | } | ||
942 | |||
943 | llinfos << "Destroying Window" << llendl; | ||
944 | |||
945 | // Don't process events in our mainWindowProc any longer. | ||
946 | SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); | ||
947 | |||
948 | // Make sure we don't leave a blank toolbar button. | ||
949 | ShowWindow(mWindowHandle, SW_HIDE); | ||
950 | |||
951 | // This causes WM_DESTROY to be sent *immediately* | ||
952 | if (!DestroyWindow(mWindowHandle)) | ||
953 | { | ||
954 | OSMessageBox("DestroyWindow(mWindowHandle) failed", "Shutdown Error", OSMB_OK); | ||
955 | } | ||
956 | |||
957 | mWindowHandle = NULL; | ||
958 | } | ||
959 | |||
960 | BOOL LLWindowWin32::isValid() | ||
961 | { | ||
962 | return (mWindowHandle != NULL); | ||
963 | } | ||
964 | |||
965 | BOOL LLWindowWin32::getVisible() | ||
966 | { | ||
967 | return (mWindowHandle && IsWindowVisible(mWindowHandle)); | ||
968 | } | ||
969 | |||
970 | BOOL LLWindowWin32::getMinimized() | ||
971 | { | ||
972 | return (mWindowHandle && IsIconic(mWindowHandle)); | ||
973 | } | ||
974 | |||
975 | BOOL LLWindowWin32::getMaximized() | ||
976 | { | ||
977 | return (mWindowHandle && IsZoomed(mWindowHandle)); | ||
978 | } | ||
979 | |||
980 | BOOL LLWindowWin32::maximize() | ||
981 | { | ||
982 | BOOL success = FALSE; | ||
983 | if (!mWindowHandle) return success; | ||
984 | |||
985 | WINDOWPLACEMENT placement; | ||
986 | placement.length = sizeof(WINDOWPLACEMENT); | ||
987 | |||
988 | success = GetWindowPlacement(mWindowHandle, &placement); | ||
989 | if (!success) return success; | ||
990 | |||
991 | placement.showCmd = SW_MAXIMIZE; | ||
992 | |||
993 | success = SetWindowPlacement(mWindowHandle, &placement); | ||
994 | return success; | ||
995 | } | ||
996 | |||
997 | BOOL LLWindowWin32::getFullscreen() | ||
998 | { | ||
999 | return mFullscreen; | ||
1000 | } | ||
1001 | |||
1002 | BOOL LLWindowWin32::getPosition(LLCoordScreen *position) | ||
1003 | { | ||
1004 | RECT window_rect; | ||
1005 | |||
1006 | if (!mWindowHandle || | ||
1007 | !GetWindowRect(mWindowHandle, &window_rect) || | ||
1008 | NULL == position) | ||
1009 | { | ||
1010 | return FALSE; | ||
1011 | } | ||
1012 | |||
1013 | position->mX = window_rect.left; | ||
1014 | position->mY = window_rect.top; | ||
1015 | return TRUE; | ||
1016 | } | ||
1017 | |||
1018 | BOOL LLWindowWin32::getSize(LLCoordScreen *size) | ||
1019 | { | ||
1020 | RECT window_rect; | ||
1021 | |||
1022 | if (!mWindowHandle || | ||
1023 | !GetWindowRect(mWindowHandle, &window_rect) || | ||
1024 | NULL == size) | ||
1025 | { | ||
1026 | return FALSE; | ||
1027 | } | ||
1028 | |||
1029 | size->mX = window_rect.right - window_rect.left; | ||
1030 | size->mY = window_rect.bottom - window_rect.top; | ||
1031 | return TRUE; | ||
1032 | } | ||
1033 | |||
1034 | BOOL LLWindowWin32::getSize(LLCoordWindow *size) | ||
1035 | { | ||
1036 | RECT client_rect; | ||
1037 | |||
1038 | if (!mWindowHandle || | ||
1039 | !GetClientRect(mWindowHandle, &client_rect) || | ||
1040 | NULL == size) | ||
1041 | { | ||
1042 | return FALSE; | ||
1043 | } | ||
1044 | |||
1045 | size->mX = client_rect.right - client_rect.left; | ||
1046 | size->mY = client_rect.bottom - client_rect.top; | ||
1047 | return TRUE; | ||
1048 | } | ||
1049 | |||
1050 | BOOL LLWindowWin32::setPosition(const LLCoordScreen position) | ||
1051 | { | ||
1052 | LLCoordScreen size; | ||
1053 | |||
1054 | if (!mWindowHandle) | ||
1055 | { | ||
1056 | return FALSE; | ||
1057 | } | ||
1058 | getSize(&size); | ||
1059 | moveWindow(position, size); | ||
1060 | return TRUE; | ||
1061 | } | ||
1062 | |||
1063 | BOOL LLWindowWin32::setSize(const LLCoordScreen size) | ||
1064 | { | ||
1065 | LLCoordScreen position; | ||
1066 | |||
1067 | getPosition(&position); | ||
1068 | if (!mWindowHandle) | ||
1069 | { | ||
1070 | return FALSE; | ||
1071 | } | ||
1072 | |||
1073 | moveWindow(position, size); | ||
1074 | return TRUE; | ||
1075 | } | ||
1076 | |||
1077 | // changing fullscreen resolution | ||
1078 | BOOL LLWindowWin32::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) | ||
1079 | { | ||
1080 | GLuint pixel_format; | ||
1081 | DEVMODE dev_mode; | ||
1082 | DWORD current_refresh; | ||
1083 | DWORD dw_ex_style; | ||
1084 | DWORD dw_style; | ||
1085 | RECT window_rect; | ||
1086 | S32 width = size.mX; | ||
1087 | S32 height = size.mY; | ||
1088 | |||
1089 | resetDisplayResolution(); | ||
1090 | |||
1091 | if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) | ||
1092 | { | ||
1093 | current_refresh = dev_mode.dmDisplayFrequency; | ||
1094 | } | ||
1095 | else | ||
1096 | { | ||
1097 | current_refresh = 60; | ||
1098 | } | ||
1099 | |||
1100 | gGLManager.shutdownGL(); | ||
1101 | //destroy gl context | ||
1102 | if (mhRC) | ||
1103 | { | ||
1104 | if (!wglMakeCurrent(NULL, NULL)) | ||
1105 | { | ||
1106 | llwarns << "Release of DC and RC failed" << llendl; | ||
1107 | } | ||
1108 | |||
1109 | if (!wglDeleteContext(mhRC)) | ||
1110 | { | ||
1111 | llwarns << "Release of rendering context failed" << llendl; | ||
1112 | } | ||
1113 | |||
1114 | mhRC = NULL; | ||
1115 | } | ||
1116 | |||
1117 | if (fullscreen) | ||
1118 | { | ||
1119 | mFullscreen = TRUE; | ||
1120 | BOOL success = FALSE; | ||
1121 | DWORD closest_refresh = 0; | ||
1122 | |||
1123 | for (S32 mode_num = 0;; mode_num++) | ||
1124 | { | ||
1125 | if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) | ||
1126 | { | ||
1127 | break; | ||
1128 | } | ||
1129 | |||
1130 | if (dev_mode.dmPelsWidth == width && | ||
1131 | dev_mode.dmPelsHeight == height && | ||
1132 | dev_mode.dmBitsPerPel == BITS_PER_PIXEL) | ||
1133 | { | ||
1134 | success = TRUE; | ||
1135 | if ((dev_mode.dmDisplayFrequency - current_refresh) | ||
1136 | < (closest_refresh - current_refresh)) | ||
1137 | { | ||
1138 | closest_refresh = dev_mode.dmDisplayFrequency; | ||
1139 | } | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | if (closest_refresh == 0) | ||
1144 | { | ||
1145 | llwarns << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << llendl; | ||
1146 | return FALSE; | ||
1147 | } | ||
1148 | |||
1149 | // If we found a good resolution, use it. | ||
1150 | if (success) | ||
1151 | { | ||
1152 | success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); | ||
1153 | } | ||
1154 | |||
1155 | // Keep a copy of the actual current device mode in case we minimize | ||
1156 | // and change the screen resolution. JC | ||
1157 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); | ||
1158 | |||
1159 | if (success) | ||
1160 | { | ||
1161 | mFullscreen = TRUE; | ||
1162 | mFullscreenWidth = dev_mode.dmPelsWidth; | ||
1163 | mFullscreenHeight = dev_mode.dmPelsHeight; | ||
1164 | mFullscreenBits = dev_mode.dmBitsPerPel; | ||
1165 | mFullscreenRefresh = dev_mode.dmDisplayFrequency; | ||
1166 | |||
1167 | llinfos << "Running at " << dev_mode.dmPelsWidth | ||
1168 | << "x" << dev_mode.dmPelsHeight | ||
1169 | << "x" << dev_mode.dmBitsPerPel | ||
1170 | << " @ " << dev_mode.dmDisplayFrequency | ||
1171 | << llendl; | ||
1172 | |||
1173 | window_rect.left = (long) 0; | ||
1174 | window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel | ||
1175 | window_rect.top = (long) 0; | ||
1176 | window_rect.bottom = (long) height; | ||
1177 | dw_ex_style = WS_EX_APPWINDOW; | ||
1178 | dw_style = WS_POPUP; | ||
1179 | |||
1180 | // Move window borders out not to cover window contents | ||
1181 | AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); | ||
1182 | } | ||
1183 | // If it failed, we don't want to run fullscreen | ||
1184 | else | ||
1185 | { | ||
1186 | mFullscreen = FALSE; | ||
1187 | mFullscreenWidth = -1; | ||
1188 | mFullscreenHeight = -1; | ||
1189 | mFullscreenBits = -1; | ||
1190 | mFullscreenRefresh = -1; | ||
1191 | |||
1192 | llinfos << "Unable to run fullscreen at " << width << "x" << height << llendl; | ||
1193 | llinfos << "Running in window." << llendl; | ||
1194 | return FALSE; | ||
1195 | } | ||
1196 | } | ||
1197 | else | ||
1198 | { | ||
1199 | mFullscreen = FALSE; | ||
1200 | window_rect.left = (long) 0; | ||
1201 | window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel | ||
1202 | window_rect.top = (long) 0; | ||
1203 | window_rect.bottom = (long) height; | ||
1204 | // Window with an edge | ||
1205 | dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; | ||
1206 | dw_style = WS_OVERLAPPEDWINDOW; | ||
1207 | } | ||
1208 | |||
1209 | // don't post quit messages when destroying old windows | ||
1210 | mPostQuit = FALSE; | ||
1211 | |||
1212 | // create window | ||
1213 | DestroyWindow(mWindowHandle); | ||
1214 | mWindowHandle = CreateWindowEx(dw_ex_style, | ||
1215 | mWindowClassName, | ||
1216 | mWindowTitle, | ||
1217 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, | ||
1218 | window_rect.left, // x pos | ||
1219 | window_rect.top, // y pos | ||
1220 | window_rect.right - window_rect.left, // width | ||
1221 | window_rect.bottom - window_rect.top, // height | ||
1222 | NULL, | ||
1223 | NULL, | ||
1224 | mhInstance, | ||
1225 | NULL); | ||
1226 | |||
1227 | //----------------------------------------------------------------------- | ||
1228 | // Create GL drawing context | ||
1229 | //----------------------------------------------------------------------- | ||
1230 | static PIXELFORMATDESCRIPTOR pfd = | ||
1231 | { | ||
1232 | sizeof(PIXELFORMATDESCRIPTOR), | ||
1233 | 1, | ||
1234 | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, | ||
1235 | PFD_TYPE_RGBA, | ||
1236 | BITS_PER_PIXEL, | ||
1237 | 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused | ||
1238 | 8, // alpha bits | ||
1239 | 0, // alpha shift | ||
1240 | 0, // accum bits | ||
1241 | 0, 0, 0, 0, // accum RGBA | ||
1242 | 24, // depth bits | ||
1243 | 8, // stencil bits, avi added for stencil test | ||
1244 | 0, | ||
1245 | PFD_MAIN_PLANE, | ||
1246 | 0, | ||
1247 | 0, 0, 0 | ||
1248 | }; | ||
1249 | |||
1250 | if (!(mhDC = GetDC(mWindowHandle))) | ||
1251 | { | ||
1252 | close(); | ||
1253 | OSMessageBox("Can't make GL device context", "Error", OSMB_OK); | ||
1254 | return FALSE; | ||
1255 | } | ||
1256 | |||
1257 | if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) | ||
1258 | { | ||
1259 | close(); | ||
1260 | OSMessageBox("Can't find suitable pixel format", "Error", OSMB_OK); | ||
1261 | return FALSE; | ||
1262 | } | ||
1263 | |||
1264 | // Verify what pixel format we actually received. | ||
1265 | if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), | ||
1266 | &pfd)) | ||
1267 | { | ||
1268 | close(); | ||
1269 | OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); | ||
1270 | return FALSE; | ||
1271 | } | ||
1272 | |||
1273 | if (pfd.cColorBits < 32) | ||
1274 | { | ||
1275 | close(); | ||
1276 | OSMessageBox( | ||
1277 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
1278 | "Please go to Control Panels -> Display -> Settings and\n" | ||
1279 | "set the screen to 32-bit color.\n" | ||
1280 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
1281 | "will automatically adjust the screen each time it runs.", | ||
1282 | "Error", | ||
1283 | OSMB_OK); | ||
1284 | return FALSE; | ||
1285 | } | ||
1286 | |||
1287 | if (pfd.cAlphaBits < 8) | ||
1288 | { | ||
1289 | close(); | ||
1290 | OSMessageBox( | ||
1291 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
1292 | "channel. Usually this is due to video card driver issues.\n" | ||
1293 | "Please make sure you have the latest video card drivers installed.\n" | ||
1294 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
1295 | "Control Panels -> Display -> Settings.\n" | ||
1296 | "If you continue to receive this message, contact customer service.", | ||
1297 | "Error", | ||
1298 | OSMB_OK); | ||
1299 | return FALSE; | ||
1300 | } | ||
1301 | |||
1302 | if (!SetPixelFormat(mhDC, pixel_format, &pfd)) | ||
1303 | { | ||
1304 | close(); | ||
1305 | OSMessageBox("Can't set pixel format", "Error", OSMB_OK); | ||
1306 | return FALSE; | ||
1307 | } | ||
1308 | |||
1309 | if (!(mhRC = wglCreateContext(mhDC))) | ||
1310 | { | ||
1311 | close(); | ||
1312 | OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); | ||
1313 | return FALSE; | ||
1314 | } | ||
1315 | |||
1316 | if (!wglMakeCurrent(mhDC, mhRC)) | ||
1317 | { | ||
1318 | close(); | ||
1319 | OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); | ||
1320 | return FALSE; | ||
1321 | } | ||
1322 | |||
1323 | gGLManager.initWGL(); | ||
1324 | |||
1325 | if (wglChoosePixelFormatARB) | ||
1326 | { | ||
1327 | // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we | ||
1328 | // can get exactly what we want. | ||
1329 | GLint attrib_list[256]; | ||
1330 | S32 cur_attrib = 0; | ||
1331 | |||
1332 | attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; | ||
1333 | attrib_list[cur_attrib++] = 24; | ||
1334 | |||
1335 | attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; | ||
1336 | attrib_list[cur_attrib++] = 8; | ||
1337 | |||
1338 | attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; | ||
1339 | attrib_list[cur_attrib++] = GL_TRUE; | ||
1340 | |||
1341 | attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; | ||
1342 | attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; | ||
1343 | |||
1344 | attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; | ||
1345 | attrib_list[cur_attrib++] = GL_TRUE; | ||
1346 | |||
1347 | attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; | ||
1348 | attrib_list[cur_attrib++] = GL_TRUE; | ||
1349 | |||
1350 | attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; | ||
1351 | attrib_list[cur_attrib++] = 24; | ||
1352 | |||
1353 | attrib_list[cur_attrib++] = WGL_RED_BITS_ARB; | ||
1354 | attrib_list[cur_attrib++] = 8; | ||
1355 | |||
1356 | attrib_list[cur_attrib++] = WGL_GREEN_BITS_ARB; | ||
1357 | attrib_list[cur_attrib++] = 8; | ||
1358 | |||
1359 | attrib_list[cur_attrib++] = WGL_BLUE_BITS_ARB; | ||
1360 | attrib_list[cur_attrib++] = 8; | ||
1361 | |||
1362 | attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; | ||
1363 | attrib_list[cur_attrib++] = 8; | ||
1364 | |||
1365 | // End the list | ||
1366 | attrib_list[cur_attrib++] = 0; | ||
1367 | |||
1368 | GLint pixel_formats[256]; | ||
1369 | U32 num_formats = 0; | ||
1370 | |||
1371 | // First we try and get a 32 bit depth pixel format | ||
1372 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
1373 | if (!result) | ||
1374 | { | ||
1375 | close(); | ||
1376 | show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); | ||
1377 | return FALSE; | ||
1378 | } | ||
1379 | |||
1380 | if (!num_formats) | ||
1381 | { | ||
1382 | llinfos << "No 32 bit z-buffer, trying 24 bits instead" << llendl; | ||
1383 | // Try 24-bit format | ||
1384 | attrib_list[1] = 24; | ||
1385 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
1386 | if (!result) | ||
1387 | { | ||
1388 | close(); | ||
1389 | show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); | ||
1390 | return FALSE; | ||
1391 | } | ||
1392 | |||
1393 | if (!num_formats) | ||
1394 | { | ||
1395 | llwarns << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << llendl; | ||
1396 | attrib_list[1] = 16; | ||
1397 | BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); | ||
1398 | if (!result || !num_formats) | ||
1399 | { | ||
1400 | close(); | ||
1401 | show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); | ||
1402 | return FALSE; | ||
1403 | } | ||
1404 | } | ||
1405 | |||
1406 | llinfos << "Choosing pixel formats: " << num_formats << " pixel formats returned" << llendl; | ||
1407 | |||
1408 | pixel_format = pixel_formats[0]; | ||
1409 | } | ||
1410 | |||
1411 | DestroyWindow(mWindowHandle); | ||
1412 | mWindowHandle = CreateWindowEx(dw_ex_style, | ||
1413 | mWindowClassName, | ||
1414 | mWindowTitle, | ||
1415 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, | ||
1416 | window_rect.left, // x pos | ||
1417 | window_rect.top, // y pos | ||
1418 | window_rect.right - window_rect.left, // width | ||
1419 | window_rect.bottom - window_rect.top, // height | ||
1420 | NULL, | ||
1421 | NULL, | ||
1422 | mhInstance, | ||
1423 | NULL); | ||
1424 | |||
1425 | if (!(mhDC = GetDC(mWindowHandle))) | ||
1426 | { | ||
1427 | close(); | ||
1428 | OSMessageBox("Can't make GL device context", "Error", OSMB_OK); | ||
1429 | return FALSE; | ||
1430 | } | ||
1431 | |||
1432 | if (!SetPixelFormat(mhDC, pixel_format, &pfd)) | ||
1433 | { | ||
1434 | close(); | ||
1435 | OSMessageBox("Can't set pixel format", "Error", OSMB_OK); | ||
1436 | return FALSE; | ||
1437 | } | ||
1438 | |||
1439 | int swap_method = 0; | ||
1440 | GLint swap_query = WGL_SWAP_METHOD_ARB; | ||
1441 | |||
1442 | if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) | ||
1443 | { | ||
1444 | switch (swap_method) | ||
1445 | { | ||
1446 | case WGL_SWAP_EXCHANGE_ARB: | ||
1447 | mSwapMethod = SWAP_METHOD_EXCHANGE; | ||
1448 | llinfos << "Swap Method: Exchange" << llendl; | ||
1449 | break; | ||
1450 | case WGL_SWAP_COPY_ARB: | ||
1451 | mSwapMethod = SWAP_METHOD_COPY; | ||
1452 | llinfos << "Swap Method: Copy" << llendl; | ||
1453 | break; | ||
1454 | case WGL_SWAP_UNDEFINED_ARB: | ||
1455 | mSwapMethod = SWAP_METHOD_UNDEFINED; | ||
1456 | llinfos << "Swap Method: Undefined" << llendl; | ||
1457 | break; | ||
1458 | default: | ||
1459 | mSwapMethod = SWAP_METHOD_UNDEFINED; | ||
1460 | llinfos << "Swap Method: Unknown" << llendl; | ||
1461 | break; | ||
1462 | } | ||
1463 | } | ||
1464 | } | ||
1465 | else | ||
1466 | { | ||
1467 | llwarns << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << llendl; | ||
1468 | } | ||
1469 | |||
1470 | // Verify what pixel format we actually received. | ||
1471 | if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), | ||
1472 | &pfd)) | ||
1473 | { | ||
1474 | close(); | ||
1475 | OSMessageBox("Can't get pixel format description", "Error", OSMB_OK); | ||
1476 | return FALSE; | ||
1477 | } | ||
1478 | |||
1479 | llinfos << "GL buffer: Color Bits " << S32(pfd.cColorBits) | ||
1480 | << " Alpha Bits " << S32(pfd.cAlphaBits) | ||
1481 | << " Depth Bits " << S32(pfd.cDepthBits) | ||
1482 | << llendl; | ||
1483 | |||
1484 | if (pfd.cColorBits < 32) | ||
1485 | { | ||
1486 | close(); | ||
1487 | OSMessageBox( | ||
1488 | "Second Life requires True Color (32-bit) to run in a window.\n" | ||
1489 | "Please go to Control Panels -> Display -> Settings and\n" | ||
1490 | "set the screen to 32-bit color.\n" | ||
1491 | "Alternately, if you choose to run fullscreen, Second Life\n" | ||
1492 | "will automatically adjust the screen each time it runs.", | ||
1493 | "Error", | ||
1494 | OSMB_OK); | ||
1495 | return FALSE; | ||
1496 | } | ||
1497 | |||
1498 | if (pfd.cAlphaBits < 8) | ||
1499 | { | ||
1500 | close(); | ||
1501 | OSMessageBox( | ||
1502 | "Second Life is unable to run because it can't get an 8 bit alpha\n" | ||
1503 | "channel. Usually this is due to video card driver issues.\n" | ||
1504 | "Please make sure you have the latest video card drivers installed.\n" | ||
1505 | "Also be sure your monitor is set to True Color (32-bit) in\n" | ||
1506 | "Control Panels -> Display -> Settings.\n" | ||
1507 | "If you continue to receive this message, contact customer service.", | ||
1508 | "Error", | ||
1509 | OSMB_OK); | ||
1510 | return FALSE; | ||
1511 | } | ||
1512 | |||
1513 | if (!(mhRC = wglCreateContext(mhDC))) | ||
1514 | { | ||
1515 | close(); | ||
1516 | OSMessageBox("Can't create GL rendering context", "Error", OSMB_OK); | ||
1517 | return FALSE; | ||
1518 | } | ||
1519 | |||
1520 | if (!wglMakeCurrent(mhDC, mhRC)) | ||
1521 | { | ||
1522 | close(); | ||
1523 | OSMessageBox("Can't activate GL rendering context", "Error", OSMB_OK); | ||
1524 | return FALSE; | ||
1525 | } | ||
1526 | |||
1527 | if (!gGLManager.initGL()) | ||
1528 | { | ||
1529 | close(); | ||
1530 | OSMessageBox( | ||
1531 | "Second Life is unable to run because your video card drivers\n" | ||
1532 | "are out of date or unsupported. Please make sure you have\n" | ||
1533 | "the latest video card drivers installed.\n\n" | ||
1534 | "If you continue to receive this message, contact customer service.", | ||
1535 | "Error", | ||
1536 | OSMB_OK); | ||
1537 | return FALSE; | ||
1538 | } | ||
1539 | |||
1540 | // Disable vertical sync for swap | ||
1541 | if (disable_vsync && wglSwapIntervalEXT) | ||
1542 | { | ||
1543 | llinfos << "Disabling vertical sync" << llendl; | ||
1544 | wglSwapIntervalEXT(0); | ||
1545 | } | ||
1546 | else | ||
1547 | { | ||
1548 | llinfos << "Keeping vertical sync" << llendl; | ||
1549 | } | ||
1550 | |||
1551 | SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); | ||
1552 | show(); | ||
1553 | |||
1554 | // ok to post quit messages now | ||
1555 | mPostQuit = TRUE; | ||
1556 | return TRUE; | ||
1557 | } | ||
1558 | |||
1559 | void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) | ||
1560 | { | ||
1561 | if( mIsMouseClipping ) | ||
1562 | { | ||
1563 | RECT client_rect_in_screen_space; | ||
1564 | if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) | ||
1565 | { | ||
1566 | ClipCursor( &client_rect_in_screen_space ); | ||
1567 | } | ||
1568 | } | ||
1569 | |||
1570 | MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); | ||
1571 | } | ||
1572 | |||
1573 | BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) | ||
1574 | { | ||
1575 | LLCoordScreen screen_pos; | ||
1576 | |||
1577 | mMousePositionModified = TRUE; | ||
1578 | if (!mWindowHandle) | ||
1579 | { | ||
1580 | return FALSE; | ||
1581 | } | ||
1582 | |||
1583 | if (!convertCoords(position, &screen_pos)) | ||
1584 | { | ||
1585 | return FALSE; | ||
1586 | } | ||
1587 | |||
1588 | return SetCursorPos(screen_pos.mX, screen_pos.mY); | ||
1589 | } | ||
1590 | |||
1591 | BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) | ||
1592 | { | ||
1593 | POINT cursor_point; | ||
1594 | LLCoordScreen screen_pos; | ||
1595 | |||
1596 | if (!mWindowHandle || | ||
1597 | !GetCursorPos(&cursor_point)) | ||
1598 | { | ||
1599 | return FALSE; | ||
1600 | } | ||
1601 | |||
1602 | screen_pos.mX = cursor_point.x; | ||
1603 | screen_pos.mY = cursor_point.y; | ||
1604 | |||
1605 | return convertCoords(screen_pos, position); | ||
1606 | } | ||
1607 | |||
1608 | void LLWindowWin32::hideCursor() | ||
1609 | { | ||
1610 | while (ShowCursor(FALSE) >= 0) | ||
1611 | { | ||
1612 | // nothing, wait for cursor to push down | ||
1613 | } | ||
1614 | mCursorHidden = TRUE; | ||
1615 | mHideCursorPermanent = TRUE; | ||
1616 | } | ||
1617 | |||
1618 | void LLWindowWin32::showCursor() | ||
1619 | { | ||
1620 | // makes sure the cursor shows up | ||
1621 | while (ShowCursor(TRUE) < 0) | ||
1622 | { | ||
1623 | // do nothing, wait for cursor to pop out | ||
1624 | } | ||
1625 | mCursorHidden = FALSE; | ||
1626 | mHideCursorPermanent = FALSE; | ||
1627 | } | ||
1628 | |||
1629 | void LLWindowWin32::showCursorFromMouseMove() | ||
1630 | { | ||
1631 | if (!mHideCursorPermanent) | ||
1632 | { | ||
1633 | showCursor(); | ||
1634 | } | ||
1635 | } | ||
1636 | |||
1637 | void LLWindowWin32::hideCursorUntilMouseMove() | ||
1638 | { | ||
1639 | if (!mHideCursorPermanent) | ||
1640 | { | ||
1641 | hideCursor(); | ||
1642 | mHideCursorPermanent = FALSE; | ||
1643 | } | ||
1644 | } | ||
1645 | |||
1646 | BOOL LLWindowWin32::isCursorHidden() | ||
1647 | { | ||
1648 | return mCursorHidden; | ||
1649 | } | ||
1650 | |||
1651 | |||
1652 | HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) | ||
1653 | { | ||
1654 | return (HCURSOR)LoadImage(mhInstance, | ||
1655 | name, | ||
1656 | IMAGE_CURSOR, | ||
1657 | 0, // default width | ||
1658 | 0, // default height | ||
1659 | LR_DEFAULTCOLOR); | ||
1660 | } | ||
1661 | |||
1662 | |||
1663 | void LLWindowWin32::initCursors() | ||
1664 | { | ||
1665 | mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); | ||
1666 | mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); | ||
1667 | mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); | ||
1668 | mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); | ||
1669 | mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); | ||
1670 | mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); | ||
1671 | mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); | ||
1672 | mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); | ||
1673 | mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); | ||
1674 | mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); | ||
1675 | mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); | ||
1676 | |||
1677 | HMODULE module = GetModuleHandle(NULL); | ||
1678 | mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); | ||
1679 | mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); | ||
1680 | mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); | ||
1681 | mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); | ||
1682 | mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); | ||
1683 | mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); | ||
1684 | mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); | ||
1685 | mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); | ||
1686 | mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); | ||
1687 | mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); | ||
1688 | mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); | ||
1689 | mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); | ||
1690 | mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); | ||
1691 | mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); | ||
1692 | mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); | ||
1693 | mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); | ||
1694 | mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); | ||
1695 | mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); | ||
1696 | mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); | ||
1697 | |||
1698 | // Color cursors | ||
1699 | mCursor[UI_CURSOR_TOOLSIT] = loadColorCursor(TEXT("TOOLSIT")); | ||
1700 | mCursor[UI_CURSOR_TOOLBUY] = loadColorCursor(TEXT("TOOLBUY")); | ||
1701 | mCursor[UI_CURSOR_TOOLPAY] = loadColorCursor(TEXT("TOOLPAY")); | ||
1702 | mCursor[UI_CURSOR_TOOLOPEN] = loadColorCursor(TEXT("TOOLOPEN")); | ||
1703 | |||
1704 | // Note: custom cursors that are not found make LoadCursor() return NULL. | ||
1705 | for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) | ||
1706 | { | ||
1707 | if( !mCursor[i] ) | ||
1708 | { | ||
1709 | mCursor[i] = LoadCursor(NULL, IDC_ARROW); | ||
1710 | } | ||
1711 | } | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | |||
1716 | void LLWindowWin32::setCursor(ECursorType cursor) | ||
1717 | { | ||
1718 | if (cursor == UI_CURSOR_ARROW | ||
1719 | && mBusyCount > 0) | ||
1720 | { | ||
1721 | cursor = UI_CURSOR_WORKING; | ||
1722 | } | ||
1723 | |||
1724 | if( mCurrentCursor != cursor ) | ||
1725 | { | ||
1726 | mCurrentCursor = cursor; | ||
1727 | SetCursor( mCursor[cursor] ); | ||
1728 | } | ||
1729 | } | ||
1730 | |||
1731 | ECursorType LLWindowWin32::getCursor() | ||
1732 | { | ||
1733 | return mCurrentCursor; | ||
1734 | } | ||
1735 | |||
1736 | void LLWindowWin32::captureMouse() | ||
1737 | { | ||
1738 | SetCapture(mWindowHandle); | ||
1739 | } | ||
1740 | |||
1741 | void LLWindowWin32::releaseMouse() | ||
1742 | { | ||
1743 | ReleaseCapture(); | ||
1744 | } | ||
1745 | |||
1746 | |||
1747 | void LLWindowWin32::delayInputProcessing() | ||
1748 | { | ||
1749 | mInputProcessingPaused = TRUE; | ||
1750 | } | ||
1751 | |||
1752 | void LLWindowWin32::gatherInput() | ||
1753 | { | ||
1754 | MSG msg; | ||
1755 | int msg_count = 0; | ||
1756 | |||
1757 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE) | ||
1758 | { | ||
1759 | TranslateMessage(&msg); | ||
1760 | DispatchMessage(&msg); | ||
1761 | msg_count++; | ||
1762 | |||
1763 | if ( mInputProcessingPaused ) | ||
1764 | { | ||
1765 | break; | ||
1766 | } | ||
1767 | /* Attempted workaround for problem where typing fast and hitting | ||
1768 | return would result in only part of the text being sent. JC | ||
1769 | |||
1770 | BOOL key_posted = TranslateMessage(&msg); | ||
1771 | DispatchMessage(&msg); | ||
1772 | msg_count++; | ||
1773 | |||
1774 | // If a key was translated, a WM_CHAR might have been posted to the end | ||
1775 | // of the event queue. We need it immediately. | ||
1776 | if (key_posted && msg.message == WM_KEYDOWN) | ||
1777 | { | ||
1778 | if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) | ||
1779 | { | ||
1780 | TranslateMessage(&msg); | ||
1781 | DispatchMessage(&msg); | ||
1782 | msg_count++; | ||
1783 | } | ||
1784 | } | ||
1785 | */ | ||
1786 | |||
1787 | // For async host by name support. Really hacky. | ||
1788 | if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) | ||
1789 | { | ||
1790 | gAsyncMsgCallback(msg); | ||
1791 | } | ||
1792 | } | ||
1793 | |||
1794 | mInputProcessingPaused = FALSE; | ||
1795 | |||
1796 | // clear this once we've processed all mouse messages that might have occurred after | ||
1797 | // we slammed the mouse position | ||
1798 | mMousePositionModified = FALSE; | ||
1799 | } | ||
1800 | |||
1801 | LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) | ||
1802 | { | ||
1803 | LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA); | ||
1804 | |||
1805 | if (NULL != window_imp) | ||
1806 | { | ||
1807 | // Has user provided their own window callback? | ||
1808 | if (NULL != window_imp->mWndProc) | ||
1809 | { | ||
1810 | if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) | ||
1811 | { | ||
1812 | // user has handled window message | ||
1813 | return 0; | ||
1814 | } | ||
1815 | } | ||
1816 | |||
1817 | // Juggle to make sure we can get negative positions for when | ||
1818 | // mouse is outside window. | ||
1819 | LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); | ||
1820 | |||
1821 | // This doesn't work, as LOWORD returns unsigned short. | ||
1822 | //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); | ||
1823 | LLCoordGL gl_coord; | ||
1824 | |||
1825 | // pass along extended flag in mask | ||
1826 | MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; | ||
1827 | BOOL eat_keystroke = TRUE; | ||
1828 | |||
1829 | switch(u_msg) | ||
1830 | { | ||
1831 | RECT update_rect; | ||
1832 | S32 update_width; | ||
1833 | S32 update_height; | ||
1834 | |||
1835 | case WM_TIMER: | ||
1836 | window_imp->updateJoystick( ); | ||
1837 | break; | ||
1838 | |||
1839 | case WM_PAINT: | ||
1840 | GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); | ||
1841 | update_width = update_rect.right - update_rect.left + 1; | ||
1842 | update_height = update_rect.bottom - update_rect.top + 1; | ||
1843 | window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, | ||
1844 | update_width, update_height); | ||
1845 | break; | ||
1846 | case WM_PARENTNOTIFY: | ||
1847 | u_msg = u_msg; | ||
1848 | break; | ||
1849 | |||
1850 | case WM_SETCURSOR: | ||
1851 | // This message is sent whenever the cursor is moved in a window. | ||
1852 | // You need to set the appropriate cursor appearance. | ||
1853 | |||
1854 | // Only take control of cursor over client region of window | ||
1855 | // This allows Windows(tm) to handle resize cursors, etc. | ||
1856 | if (LOWORD(l_param) == HTCLIENT) | ||
1857 | { | ||
1858 | SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] ); | ||
1859 | return 0; | ||
1860 | } | ||
1861 | break; | ||
1862 | |||
1863 | case WM_ENTERMENULOOP: | ||
1864 | window_imp->mCallbacks->handleWindowBlock(window_imp); | ||
1865 | break; | ||
1866 | |||
1867 | case WM_EXITMENULOOP: | ||
1868 | window_imp->mCallbacks->handleWindowUnblock(window_imp); | ||
1869 | break; | ||
1870 | |||
1871 | case WM_ACTIVATEAPP: | ||
1872 | { | ||
1873 | // This message should be sent whenever the app gains or loses focus. | ||
1874 | BOOL activating = (BOOL) w_param; | ||
1875 | BOOL minimized = window_imp->getMinimized(); | ||
1876 | |||
1877 | if (gDebugWindowProc) | ||
1878 | { | ||
1879 | llinfos << "WINDOWPROC ActivateApp " | ||
1880 | << " activating " << S32(activating) | ||
1881 | << " minimized " << S32(minimized) | ||
1882 | << " fullscreen " << S32(window_imp->mFullscreen) | ||
1883 | << llendl; | ||
1884 | } | ||
1885 | |||
1886 | if (window_imp->mFullscreen) | ||
1887 | { | ||
1888 | // When we run fullscreen, restoring or minimizing the app needs | ||
1889 | // to switch the screen resolution | ||
1890 | if (activating) | ||
1891 | { | ||
1892 | window_imp->setFullscreenResolution(); | ||
1893 | window_imp->restore(); | ||
1894 | } | ||
1895 | else | ||
1896 | { | ||
1897 | window_imp->minimize(); | ||
1898 | window_imp->resetDisplayResolution(); | ||
1899 | } | ||
1900 | } | ||
1901 | break; | ||
1902 | } | ||
1903 | |||
1904 | case WM_ACTIVATE: | ||
1905 | { | ||
1906 | // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE | ||
1907 | BOOL activating = (LOWORD(w_param) != WA_INACTIVE); | ||
1908 | |||
1909 | BOOL minimized = BOOL(HIWORD(w_param)); | ||
1910 | |||
1911 | // JC - I'm not sure why, but if we don't report that we handled the | ||
1912 | // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work | ||
1913 | // properly when we run fullscreen. | ||
1914 | if (gDebugWindowProc) | ||
1915 | { | ||
1916 | llinfos << "WINDOWPROC Activate " | ||
1917 | << " activating " << S32(activating) | ||
1918 | << " minimized " << S32(minimized) | ||
1919 | << llendl; | ||
1920 | } | ||
1921 | |||
1922 | // Don't handle this. | ||
1923 | break; | ||
1924 | } | ||
1925 | |||
1926 | case WM_QUERYOPEN: | ||
1927 | // TODO: use this to return a nice icon | ||
1928 | break; | ||
1929 | |||
1930 | case WM_SYSCOMMAND: | ||
1931 | switch(w_param) | ||
1932 | { | ||
1933 | case SC_KEYMENU: | ||
1934 | // Disallow the ALT key from triggering the default system menu. | ||
1935 | return 0; | ||
1936 | |||
1937 | case SC_SCREENSAVE: | ||
1938 | case SC_MONITORPOWER: | ||
1939 | // eat screen save messages and prevent them! | ||
1940 | return 0; | ||
1941 | } | ||
1942 | break; | ||
1943 | |||
1944 | case WM_CLOSE: | ||
1945 | // Will the app allow the window to close? | ||
1946 | if (window_imp->mCallbacks->handleCloseRequest(window_imp)) | ||
1947 | { | ||
1948 | // Get the app to initiate cleanup. | ||
1949 | window_imp->mCallbacks->handleQuit(window_imp); | ||
1950 | // The app is responsible for calling destroyWindow when done with GL | ||
1951 | } | ||
1952 | return 0; | ||
1953 | |||
1954 | case WM_DESTROY: | ||
1955 | if (window_imp->shouldPostQuit()) | ||
1956 | { | ||
1957 | PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 | ||
1958 | } | ||
1959 | return 0; | ||
1960 | |||
1961 | case WM_COMMAND: | ||
1962 | if (!HIWORD(w_param)) // this message is from a menu | ||
1963 | { | ||
1964 | window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)); | ||
1965 | } | ||
1966 | break; | ||
1967 | |||
1968 | case WM_SYSKEYDOWN: | ||
1969 | // allow system keys, such as ALT-F4 to be processed by Windows | ||
1970 | eat_keystroke = FALSE; | ||
1971 | case WM_KEYDOWN: | ||
1972 | if (gDebugWindowProc) | ||
1973 | { | ||
1974 | llinfos << "Debug WindowProc WM_KEYDOWN " | ||
1975 | << " key " << S32(w_param) | ||
1976 | << llendl; | ||
1977 | } | ||
1978 | if (gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) | ||
1979 | { | ||
1980 | return 0; | ||
1981 | } | ||
1982 | // pass on to windows if we didn't handle it | ||
1983 | break; | ||
1984 | |||
1985 | case WM_SYSKEYUP: | ||
1986 | eat_keystroke = FALSE; | ||
1987 | case WM_KEYUP: | ||
1988 | if (gDebugWindowProc) | ||
1989 | { | ||
1990 | llinfos << "Debug WindowProc WM_KEYUP " | ||
1991 | << " key " << S32(w_param) | ||
1992 | << llendl; | ||
1993 | } | ||
1994 | if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) | ||
1995 | { | ||
1996 | return 0; | ||
1997 | } | ||
1998 | |||
1999 | // pass on to windows | ||
2000 | break; | ||
2001 | |||
2002 | |||
2003 | case WM_CHAR: | ||
2004 | // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need | ||
2005 | // to figure out how that works. - Doug | ||
2006 | // llinfos << "WM_CHAR: " << w_param << llendl; | ||
2007 | if (gDebugWindowProc) | ||
2008 | { | ||
2009 | llinfos << "Debug WindowProc WM_CHAR " | ||
2010 | << " key " << S32(w_param) | ||
2011 | << llendl; | ||
2012 | } | ||
2013 | if (window_imp->mCallbacks->handleUnicodeChar(w_param, gKeyboard->currentMask(FALSE))) | ||
2014 | { | ||
2015 | return 0; | ||
2016 | } | ||
2017 | break; | ||
2018 | |||
2019 | case WM_LBUTTONDOWN: | ||
2020 | { | ||
2021 | // Because we move the cursor position in the app, we need to query | ||
2022 | // to find out where the cursor at the time the event is handled. | ||
2023 | // If we don't do this, many clicks could get buffered up, and if the | ||
2024 | // first click changes the cursor position, all subsequent clicks | ||
2025 | // will occur at the wrong location. JC | ||
2026 | LLCoordWindow cursor_coord_window; | ||
2027 | if (window_imp->mMousePositionModified) | ||
2028 | { | ||
2029 | window_imp->getCursorPosition(&cursor_coord_window); | ||
2030 | window_imp->convertCoords(cursor_coord_window, &gl_coord); | ||
2031 | } | ||
2032 | else | ||
2033 | { | ||
2034 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2035 | } | ||
2036 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2037 | if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask)) | ||
2038 | { | ||
2039 | return 0; | ||
2040 | } | ||
2041 | } | ||
2042 | break; | ||
2043 | |||
2044 | case WM_LBUTTONDBLCLK: | ||
2045 | //RN: ignore right button double clicks for now | ||
2046 | //case WM_RBUTTONDBLCLK: | ||
2047 | { | ||
2048 | // Because we move the cursor position in the app, we need to query | ||
2049 | // to find out where the cursor at the time the event is handled. | ||
2050 | // If we don't do this, many clicks could get buffered up, and if the | ||
2051 | // first click changes the cursor position, all subsequent clicks | ||
2052 | // will occur at the wrong location. JC | ||
2053 | LLCoordWindow cursor_coord_window; | ||
2054 | if (window_imp->mMousePositionModified) | ||
2055 | { | ||
2056 | window_imp->getCursorPosition(&cursor_coord_window); | ||
2057 | window_imp->convertCoords(cursor_coord_window, &gl_coord); | ||
2058 | } | ||
2059 | else | ||
2060 | { | ||
2061 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2062 | } | ||
2063 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2064 | if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) ) | ||
2065 | { | ||
2066 | return 0; | ||
2067 | } | ||
2068 | } | ||
2069 | break; | ||
2070 | |||
2071 | case WM_LBUTTONUP: | ||
2072 | { | ||
2073 | //if (gDebugClicks) | ||
2074 | //{ | ||
2075 | // llinfos << "WndProc left button up" << llendl; | ||
2076 | //} | ||
2077 | // Because we move the cursor position in the app, we need to query | ||
2078 | // to find out where the cursor at the time the event is handled. | ||
2079 | // If we don't do this, many clicks could get buffered up, and if the | ||
2080 | // first click changes the cursor position, all subsequent clicks | ||
2081 | // will occur at the wrong location. JC | ||
2082 | LLCoordWindow cursor_coord_window; | ||
2083 | if (window_imp->mMousePositionModified) | ||
2084 | { | ||
2085 | window_imp->getCursorPosition(&cursor_coord_window); | ||
2086 | window_imp->convertCoords(cursor_coord_window, &gl_coord); | ||
2087 | } | ||
2088 | else | ||
2089 | { | ||
2090 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2091 | } | ||
2092 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2093 | if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask)) | ||
2094 | { | ||
2095 | return 0; | ||
2096 | } | ||
2097 | } | ||
2098 | break; | ||
2099 | |||
2100 | case WM_RBUTTONDBLCLK: | ||
2101 | case WM_RBUTTONDOWN: | ||
2102 | { | ||
2103 | // Because we move the cursor position in tllviewerhe app, we need to query | ||
2104 | // to find out where the cursor at the time the event is handled. | ||
2105 | // If we don't do this, many clicks could get buffered up, and if the | ||
2106 | // first click changes the cursor position, all subsequent clicks | ||
2107 | // will occur at the wrong location. JC | ||
2108 | LLCoordWindow cursor_coord_window; | ||
2109 | if (window_imp->mMousePositionModified) | ||
2110 | { | ||
2111 | window_imp->getCursorPosition(&cursor_coord_window); | ||
2112 | window_imp->convertCoords(cursor_coord_window, &gl_coord); | ||
2113 | } | ||
2114 | else | ||
2115 | { | ||
2116 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2117 | } | ||
2118 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2119 | if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask)) | ||
2120 | { | ||
2121 | return 0; | ||
2122 | } | ||
2123 | } | ||
2124 | break; | ||
2125 | |||
2126 | case WM_RBUTTONUP: | ||
2127 | { | ||
2128 | // Because we move the cursor position in the app, we need to query | ||
2129 | // to find out where the cursor at the time the event is handled. | ||
2130 | // If we don't do this, many clicks could get buffered up, and if the | ||
2131 | // first click changes the cursor position, all subsequent clicks | ||
2132 | // will occur at the wrong location. JC | ||
2133 | LLCoordWindow cursor_coord_window; | ||
2134 | if (window_imp->mMousePositionModified) | ||
2135 | { | ||
2136 | window_imp->getCursorPosition(&cursor_coord_window); | ||
2137 | window_imp->convertCoords(cursor_coord_window, &gl_coord); | ||
2138 | } | ||
2139 | else | ||
2140 | { | ||
2141 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2142 | } | ||
2143 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2144 | if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask)) | ||
2145 | { | ||
2146 | return 0; | ||
2147 | } | ||
2148 | } | ||
2149 | break; | ||
2150 | |||
2151 | case WM_MBUTTONDOWN: | ||
2152 | // Handle middle button click | ||
2153 | break; | ||
2154 | |||
2155 | case WM_MOUSEWHEEL: | ||
2156 | { | ||
2157 | static short z_delta = 0; | ||
2158 | |||
2159 | z_delta += HIWORD(w_param); | ||
2160 | // cout << "z_delta " << z_delta << endl; | ||
2161 | |||
2162 | // current mouse wheels report changes in increments of zDelta (+120, -120) | ||
2163 | // Future, higher resolution mouse wheels may report smaller deltas. | ||
2164 | // So we sum the deltas and only act when we've exceeded WHEEL_DELTA | ||
2165 | // | ||
2166 | // If the user rapidly spins the wheel, we can get messages with | ||
2167 | // large deltas, like 480 or so. Thus we need to scroll more quickly. | ||
2168 | if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) | ||
2169 | { | ||
2170 | window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA); | ||
2171 | z_delta = 0; | ||
2172 | } | ||
2173 | return 0; | ||
2174 | } | ||
2175 | /* | ||
2176 | // TODO: add this after resolving _WIN32_WINNT issue | ||
2177 | case WM_MOUSELEAVE: | ||
2178 | { | ||
2179 | window_imp->mCallbacks->handleMouseLeave(window_imp); | ||
2180 | |||
2181 | // TRACKMOUSEEVENT track_mouse_event; | ||
2182 | // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); | ||
2183 | // track_mouse_event.dwFlags = TME_LEAVE; | ||
2184 | // track_mouse_event.hwndTrack = h_wnd; | ||
2185 | // track_mouse_event.dwHoverTime = HOVER_DEFAULT; | ||
2186 | // TrackMouseEvent( &track_mouse_event ); | ||
2187 | return 0; | ||
2188 | } | ||
2189 | */ | ||
2190 | // Handle mouse movement within the window | ||
2191 | case WM_MOUSEMOVE: | ||
2192 | { | ||
2193 | window_imp->convertCoords(window_coord, &gl_coord); | ||
2194 | MASK mask = gKeyboard->currentMask(TRUE); | ||
2195 | window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); | ||
2196 | return 0; | ||
2197 | } | ||
2198 | |||
2199 | case WM_SIZE: | ||
2200 | { | ||
2201 | S32 width = S32( LOWORD(l_param) ); | ||
2202 | S32 height = S32( HIWORD(l_param) ); | ||
2203 | |||
2204 | if (gDebugWindowProc) | ||
2205 | { | ||
2206 | BOOL maximized = ( w_param == SIZE_MAXIMIZED ); | ||
2207 | BOOL restored = ( w_param == SIZE_RESTORED ); | ||
2208 | BOOL minimized = ( w_param == SIZE_MINIMIZED ); | ||
2209 | |||
2210 | llinfos << "WINDOWPROC Size " | ||
2211 | << width << "x" << height | ||
2212 | << " max " << S32(maximized) | ||
2213 | << " min " << S32(minimized) | ||
2214 | << " rest " << S32(restored) | ||
2215 | << llendl; | ||
2216 | } | ||
2217 | |||
2218 | // If we are now restored, but we weren't before, this | ||
2219 | // means that the window was un-minimized. | ||
2220 | if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) | ||
2221 | { | ||
2222 | window_imp->mCallbacks->handleActivate(window_imp, TRUE); | ||
2223 | } | ||
2224 | |||
2225 | // handle case of window being maximized from fully minimized state | ||
2226 | if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) | ||
2227 | { | ||
2228 | window_imp->mCallbacks->handleActivate(window_imp, TRUE); | ||
2229 | } | ||
2230 | |||
2231 | // Also handle the minimization case | ||
2232 | if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) | ||
2233 | { | ||
2234 | window_imp->mCallbacks->handleActivate(window_imp, FALSE); | ||
2235 | } | ||
2236 | |||
2237 | // Actually resize all of our views | ||
2238 | if (w_param != SIZE_MINIMIZED) | ||
2239 | { | ||
2240 | // Ignore updates for minimizing and minimized "windows" | ||
2241 | window_imp->mCallbacks->handleResize( window_imp, | ||
2242 | LOWORD(l_param), | ||
2243 | HIWORD(l_param) ); | ||
2244 | } | ||
2245 | |||
2246 | window_imp->mLastSizeWParam = w_param; | ||
2247 | |||
2248 | return 0; | ||
2249 | } | ||
2250 | |||
2251 | case WM_SETFOCUS: | ||
2252 | if (gDebugWindowProc) | ||
2253 | { | ||
2254 | llinfos << "WINDOWPROC SetFocus" << llendl; | ||
2255 | } | ||
2256 | window_imp->mCallbacks->handleFocus(window_imp); | ||
2257 | return 0; | ||
2258 | |||
2259 | case WM_KILLFOCUS: | ||
2260 | if (gDebugWindowProc) | ||
2261 | { | ||
2262 | llinfos << "WINDOWPROC KillFocus" << llendl; | ||
2263 | } | ||
2264 | window_imp->mCallbacks->handleFocusLost(window_imp); | ||
2265 | return 0; | ||
2266 | |||
2267 | case WM_COPYDATA: | ||
2268 | // received a URL | ||
2269 | PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param; | ||
2270 | window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData); | ||
2271 | return 0; | ||
2272 | } | ||
2273 | } | ||
2274 | |||
2275 | // pass unhandled messages down to Windows | ||
2276 | return DefWindowProc(h_wnd, u_msg, w_param, l_param); | ||
2277 | } | ||
2278 | |||
2279 | BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) | ||
2280 | { | ||
2281 | S32 client_height; | ||
2282 | RECT client_rect; | ||
2283 | LLCoordWindow window_position; | ||
2284 | |||
2285 | if (!mWindowHandle || | ||
2286 | !GetClientRect(mWindowHandle, &client_rect) || | ||
2287 | NULL == to) | ||
2288 | { | ||
2289 | return FALSE; | ||
2290 | } | ||
2291 | |||
2292 | to->mX = from.mX; | ||
2293 | client_height = client_rect.bottom - client_rect.top; | ||
2294 | to->mY = client_height - from.mY - 1; | ||
2295 | |||
2296 | return TRUE; | ||
2297 | } | ||
2298 | |||
2299 | BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) | ||
2300 | { | ||
2301 | S32 client_height; | ||
2302 | RECT client_rect; | ||
2303 | |||
2304 | if (!mWindowHandle || | ||
2305 | !GetClientRect(mWindowHandle, &client_rect) || | ||
2306 | NULL == to) | ||
2307 | { | ||
2308 | return FALSE; | ||
2309 | } | ||
2310 | |||
2311 | to->mX = from.mX; | ||
2312 | client_height = client_rect.bottom - client_rect.top; | ||
2313 | to->mY = client_height - from.mY - 1; | ||
2314 | |||
2315 | return TRUE; | ||
2316 | } | ||
2317 | |||
2318 | BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) | ||
2319 | { | ||
2320 | POINT mouse_point; | ||
2321 | |||
2322 | mouse_point.x = from.mX; | ||
2323 | mouse_point.y = from.mY; | ||
2324 | BOOL result = ScreenToClient(mWindowHandle, &mouse_point); | ||
2325 | |||
2326 | if (result) | ||
2327 | { | ||
2328 | to->mX = mouse_point.x; | ||
2329 | to->mY = mouse_point.y; | ||
2330 | } | ||
2331 | |||
2332 | return result; | ||
2333 | } | ||
2334 | |||
2335 | BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) | ||
2336 | { | ||
2337 | POINT mouse_point; | ||
2338 | |||
2339 | mouse_point.x = from.mX; | ||
2340 | mouse_point.y = from.mY; | ||
2341 | BOOL result = ClientToScreen(mWindowHandle, &mouse_point); | ||
2342 | |||
2343 | if (result) | ||
2344 | { | ||
2345 | to->mX = mouse_point.x; | ||
2346 | to->mY = mouse_point.y; | ||
2347 | } | ||
2348 | |||
2349 | return result; | ||
2350 | } | ||
2351 | |||
2352 | BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) | ||
2353 | { | ||
2354 | LLCoordWindow window_coord; | ||
2355 | |||
2356 | if (!mWindowHandle || (NULL == to)) | ||
2357 | { | ||
2358 | return FALSE; | ||
2359 | } | ||
2360 | |||
2361 | convertCoords(from, &window_coord); | ||
2362 | convertCoords(window_coord, to); | ||
2363 | return TRUE; | ||
2364 | } | ||
2365 | |||
2366 | BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) | ||
2367 | { | ||
2368 | LLCoordWindow window_coord; | ||
2369 | |||
2370 | if (!mWindowHandle || (NULL == to)) | ||
2371 | { | ||
2372 | return FALSE; | ||
2373 | } | ||
2374 | |||
2375 | convertCoords(from, &window_coord); | ||
2376 | convertCoords(window_coord, to); | ||
2377 | return TRUE; | ||
2378 | } | ||
2379 | |||
2380 | |||
2381 | BOOL LLWindowWin32::isClipboardTextAvailable() | ||
2382 | { | ||
2383 | return IsClipboardFormatAvailable(CF_UNICODETEXT) || IsClipboardFormatAvailable( CF_TEXT ); | ||
2384 | } | ||
2385 | |||
2386 | |||
2387 | BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) | ||
2388 | { | ||
2389 | BOOL success = FALSE; | ||
2390 | |||
2391 | if (IsClipboardFormatAvailable(CF_UNICODETEXT)) | ||
2392 | { | ||
2393 | if (OpenClipboard(mWindowHandle)) | ||
2394 | { | ||
2395 | HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); | ||
2396 | if (h_data) | ||
2397 | { | ||
2398 | WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); | ||
2399 | if (utf16str) | ||
2400 | { | ||
2401 | dst = utf16str_to_wstring(utf16str); | ||
2402 | LLWString::removeCRLF(dst); | ||
2403 | GlobalUnlock(h_data); | ||
2404 | success = TRUE; | ||
2405 | } | ||
2406 | } | ||
2407 | CloseClipboard(); | ||
2408 | } | ||
2409 | } | ||
2410 | else if (IsClipboardFormatAvailable(CF_TEXT)) | ||
2411 | { | ||
2412 | // This must be an OLD OS. We don't do non-ASCII for old OSes | ||
2413 | if (OpenClipboard(mWindowHandle)) | ||
2414 | { | ||
2415 | HGLOBAL h_data = GetClipboardData(CF_TEXT); | ||
2416 | if (h_data) | ||
2417 | { | ||
2418 | char* str = (char*) GlobalLock(h_data); | ||
2419 | if (str) | ||
2420 | { | ||
2421 | // Strip non-ASCII characters | ||
2422 | dst = utf8str_to_wstring(mbcsstring_makeASCII(str)); | ||
2423 | LLWString::removeCRLF(dst); | ||
2424 | GlobalUnlock(h_data); | ||
2425 | success = TRUE; | ||
2426 | } | ||
2427 | } | ||
2428 | CloseClipboard(); | ||
2429 | } | ||
2430 | } | ||
2431 | |||
2432 | return success; | ||
2433 | } | ||
2434 | |||
2435 | |||
2436 | BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) | ||
2437 | { | ||
2438 | BOOL success = FALSE; | ||
2439 | |||
2440 | if (OpenClipboard(mWindowHandle)) | ||
2441 | { | ||
2442 | EmptyClipboard(); | ||
2443 | |||
2444 | // Provide a copy of the data in Unicode format. | ||
2445 | LLWString sanitized_string(wstr); | ||
2446 | LLWString::addCRLF(sanitized_string); | ||
2447 | llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); | ||
2448 | const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); | ||
2449 | |||
2450 | // Memory is allocated and then ownership of it is transfered to the system. | ||
2451 | HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); | ||
2452 | if (hglobal_copy_utf16) | ||
2453 | { | ||
2454 | WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); | ||
2455 | if (copy_utf16) | ||
2456 | { | ||
2457 | memcpy(copy_utf16, out_utf16.c_str(), size_utf16); | ||
2458 | GlobalUnlock(hglobal_copy_utf16); | ||
2459 | |||
2460 | if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) | ||
2461 | { | ||
2462 | success = TRUE; | ||
2463 | } | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | // Also provide a copy as raw ASCII text. | ||
2468 | LLWString ascii_string(wstr); | ||
2469 | LLWString::_makeASCII(ascii_string); | ||
2470 | LLWString::addCRLF(ascii_string); | ||
2471 | std::string out_s = wstring_to_utf8str(ascii_string); | ||
2472 | const size_t size = (out_s.length() + 1) * sizeof(char); | ||
2473 | |||
2474 | // Memory is allocated and then ownership of it is transfered to the system. | ||
2475 | HGLOBAL hglobal_copy = GlobalAlloc(GMEM_MOVEABLE, size); | ||
2476 | if (hglobal_copy) | ||
2477 | { | ||
2478 | char* copy = (char*) GlobalLock(hglobal_copy); | ||
2479 | if( copy ) | ||
2480 | { | ||
2481 | memcpy(copy, out_s.c_str(), size); | ||
2482 | GlobalUnlock(hglobal_copy); | ||
2483 | |||
2484 | if (SetClipboardData(CF_TEXT, hglobal_copy)) | ||
2485 | { | ||
2486 | success = TRUE; | ||
2487 | } | ||
2488 | } | ||
2489 | } | ||
2490 | |||
2491 | CloseClipboard(); | ||
2492 | } | ||
2493 | |||
2494 | return success; | ||
2495 | } | ||
2496 | |||
2497 | // Constrains the mouse to the window. | ||
2498 | void LLWindowWin32::setMouseClipping( BOOL b ) | ||
2499 | { | ||
2500 | if( b != mIsMouseClipping ) | ||
2501 | { | ||
2502 | BOOL success = FALSE; | ||
2503 | |||
2504 | if( b ) | ||
2505 | { | ||
2506 | GetClipCursor( &mOldMouseClip ); | ||
2507 | |||
2508 | RECT client_rect_in_screen_space; | ||
2509 | if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) | ||
2510 | { | ||
2511 | success = ClipCursor( &client_rect_in_screen_space ); | ||
2512 | } | ||
2513 | } | ||
2514 | else | ||
2515 | { | ||
2516 | // Must restore the old mouse clip, which may be set by another window. | ||
2517 | success = ClipCursor( &mOldMouseClip ); | ||
2518 | SetRect( &mOldMouseClip, 0, 0, 0, 0 ); | ||
2519 | } | ||
2520 | |||
2521 | if( success ) | ||
2522 | { | ||
2523 | mIsMouseClipping = b; | ||
2524 | } | ||
2525 | } | ||
2526 | } | ||
2527 | |||
2528 | BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) | ||
2529 | { | ||
2530 | BOOL success = FALSE; | ||
2531 | |||
2532 | RECT client_rect; | ||
2533 | if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) ) | ||
2534 | { | ||
2535 | POINT top_left; | ||
2536 | top_left.x = client_rect.left; | ||
2537 | top_left.y = client_rect.top; | ||
2538 | ClientToScreen(mWindowHandle, &top_left); | ||
2539 | |||
2540 | POINT bottom_right; | ||
2541 | bottom_right.x = client_rect.right; | ||
2542 | bottom_right.y = client_rect.bottom; | ||
2543 | ClientToScreen(mWindowHandle, &bottom_right); | ||
2544 | |||
2545 | SetRect( rectp, | ||
2546 | top_left.x, | ||
2547 | top_left.y, | ||
2548 | bottom_right.x, | ||
2549 | bottom_right.y ); | ||
2550 | |||
2551 | success = TRUE; | ||
2552 | } | ||
2553 | |||
2554 | return success; | ||
2555 | } | ||
2556 | |||
2557 | |||
2558 | BOOL LLWindowWin32::sendEmail(const char* address, const char* subject, const char* body_text, | ||
2559 | const char* attachment, const char* attachment_displayed_name ) | ||
2560 | { | ||
2561 | // Based on "A SendMail() DLL" by Greg Turner, Windows Developer Magazine, Nov. 1997. | ||
2562 | // See article for use of GetProcAddress | ||
2563 | // No restrictions on use. | ||
2564 | |||
2565 | enum SendResult | ||
2566 | { | ||
2567 | LL_EMAIL_SUCCESS, | ||
2568 | LL_EMAIL_MAPI_NOT_INSTALLED, // No MAPI Server (eg Microsoft Exchange) installed | ||
2569 | LL_EMAIL_MAPILOAD_FAILED, // Load of MAPI32.DLL failed | ||
2570 | LL_EMAIL_SEND_FAILED // The message send itself failed | ||
2571 | }; | ||
2572 | |||
2573 | SendResult result = LL_EMAIL_SUCCESS; | ||
2574 | |||
2575 | U32 mapi_installed = GetProfileInt(L"Mail", L"MAPI", 0); | ||
2576 | if( !mapi_installed) | ||
2577 | { | ||
2578 | result = LL_EMAIL_MAPI_NOT_INSTALLED; | ||
2579 | } | ||
2580 | else | ||
2581 | { | ||
2582 | HINSTANCE hMAPIInst = LoadLibrary(L"MAPI32.DLL"); | ||
2583 | if(!hMAPIInst) | ||
2584 | { | ||
2585 | result = LL_EMAIL_MAPILOAD_FAILED; | ||
2586 | } | ||
2587 | else | ||
2588 | { | ||
2589 | LPMAPISENDMAIL pMAPISendMail = (LPMAPISENDMAIL) GetProcAddress(hMAPIInst, "MAPISendMail"); | ||
2590 | |||
2591 | // Send the message | ||
2592 | MapiRecipDesc recipients[1]; | ||
2593 | recipients[0].ulReserved = 0; | ||
2594 | recipients[0].ulRecipClass = MAPI_TO; | ||
2595 | recipients[0].lpszName = (char*)address; | ||
2596 | recipients[0].lpszAddress = (char*)address; | ||
2597 | recipients[0].ulEIDSize = 0; | ||
2598 | recipients[0].lpEntryID = 0; | ||
2599 | |||
2600 | MapiFileDesc files[1]; | ||
2601 | files[0].ulReserved = 0; | ||
2602 | files[0].flFlags = 0; // non-OLE file | ||
2603 | files[0].nPosition = -1; // Leave file location in email unspecified. | ||
2604 | files[0].lpszPathName = (char*)attachment; // Must be fully qualified name, including drive letter. | ||
2605 | files[0].lpszFileName = (char*)attachment_displayed_name; // If NULL, uses attachment as displayed name. | ||
2606 | files[0].lpFileType = NULL; // Recipient will have to figure out what kind of file this is. | ||
2607 | |||
2608 | MapiMessage msg; | ||
2609 | memset(&msg, 0, sizeof(msg)); | ||
2610 | msg.lpszSubject = (char*)subject; // may be NULL | ||
2611 | msg.lpszNoteText = (char*)body_text; | ||
2612 | msg.nRecipCount = address ? 1 : 0; | ||
2613 | msg.lpRecips = address ? recipients : NULL; | ||
2614 | msg.nFileCount = attachment ? 1 : 0; | ||
2615 | msg.lpFiles = attachment ? files : NULL; | ||
2616 | |||
2617 | U32 success = pMAPISendMail(0, (U32) mWindowHandle, &msg, MAPI_DIALOG|MAPI_LOGON_UI|MAPI_NEW_SESSION, 0); | ||
2618 | if(success != SUCCESS_SUCCESS) | ||
2619 | { | ||
2620 | result = LL_EMAIL_SEND_FAILED; | ||
2621 | } | ||
2622 | |||
2623 | FreeLibrary(hMAPIInst); | ||
2624 | } | ||
2625 | } | ||
2626 | |||
2627 | return result == LL_EMAIL_SUCCESS; | ||
2628 | } | ||
2629 | |||
2630 | |||
2631 | S32 LLWindowWin32::stat(const char* file_name, struct stat* stat_info) | ||
2632 | { | ||
2633 | llassert( sizeof(struct stat) == sizeof(struct _stat) ); // They are defined identically in sys/stat.h, but I'm paranoid. | ||
2634 | return LLFile::stat( file_name, (struct _stat*) stat_info ); | ||
2635 | } | ||
2636 | |||
2637 | void LLWindowWin32::flashIcon(F32 seconds) | ||
2638 | { | ||
2639 | FLASHWINFO flash_info; | ||
2640 | |||
2641 | flash_info.cbSize = sizeof(FLASHWINFO); | ||
2642 | flash_info.hwnd = mWindowHandle; | ||
2643 | flash_info.dwFlags = FLASHW_TRAY; | ||
2644 | flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); | ||
2645 | flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds | ||
2646 | FlashWindowEx(&flash_info); | ||
2647 | } | ||
2648 | |||
2649 | F32 LLWindowWin32::getGamma() | ||
2650 | { | ||
2651 | return mCurrentGamma; | ||
2652 | } | ||
2653 | |||
2654 | BOOL LLWindowWin32::restoreGamma() | ||
2655 | { | ||
2656 | return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); | ||
2657 | } | ||
2658 | |||
2659 | BOOL LLWindowWin32::setGamma(const F32 gamma) | ||
2660 | { | ||
2661 | mCurrentGamma = gamma; | ||
2662 | |||
2663 | llinfos << "Setting gamma to " << gamma << llendl; | ||
2664 | |||
2665 | for ( int i = 0; i < 256; ++i ) | ||
2666 | { | ||
2667 | int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); | ||
2668 | |||
2669 | int value = mult * i; | ||
2670 | |||
2671 | if ( value > 0xffff ) | ||
2672 | value = 0xffff; | ||
2673 | |||
2674 | mCurrentGammaRamp [ 0 * 256 + i ] = | ||
2675 | mCurrentGammaRamp [ 1 * 256 + i ] = | ||
2676 | mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value; | ||
2677 | }; | ||
2678 | |||
2679 | return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); | ||
2680 | } | ||
2681 | |||
2682 | LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) | ||
2683 | { | ||
2684 | if (!mSupportedResolutions) | ||
2685 | { | ||
2686 | mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; | ||
2687 | DEVMODE dev_mode; | ||
2688 | |||
2689 | mNumSupportedResolutions = 0; | ||
2690 | for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) | ||
2691 | { | ||
2692 | if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) | ||
2693 | { | ||
2694 | break; | ||
2695 | } | ||
2696 | |||
2697 | if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && | ||
2698 | dev_mode.dmPelsWidth >= 800 && | ||
2699 | dev_mode.dmPelsHeight >= 600) | ||
2700 | { | ||
2701 | BOOL resolution_exists = FALSE; | ||
2702 | for(S32 i = 0; i < mNumSupportedResolutions; i++) | ||
2703 | { | ||
2704 | if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && | ||
2705 | mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) | ||
2706 | { | ||
2707 | resolution_exists = TRUE; | ||
2708 | } | ||
2709 | } | ||
2710 | if (!resolution_exists) | ||
2711 | { | ||
2712 | mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; | ||
2713 | mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; | ||
2714 | mNumSupportedResolutions++; | ||
2715 | } | ||
2716 | } | ||
2717 | } | ||
2718 | } | ||
2719 | |||
2720 | num_resolutions = mNumSupportedResolutions; | ||
2721 | return mSupportedResolutions; | ||
2722 | } | ||
2723 | |||
2724 | |||
2725 | F32 LLWindowWin32::getNativeAspectRatio() | ||
2726 | { | ||
2727 | if (mOverrideAspectRatio > 0.f) | ||
2728 | { | ||
2729 | return mOverrideAspectRatio; | ||
2730 | } | ||
2731 | else if (mNativeAspectRatio > 0.f) | ||
2732 | { | ||
2733 | // we grabbed this value at startup, based on the user's desktop settings | ||
2734 | return mNativeAspectRatio; | ||
2735 | } | ||
2736 | // RN: this hack presumes that the largest supported resolution is monitor-limited | ||
2737 | // and that pixels in that mode are square, therefore defining the native aspect ratio | ||
2738 | // of the monitor...this seems to work to a close approximation for most CRTs/LCDs | ||
2739 | S32 num_resolutions; | ||
2740 | LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); | ||
2741 | |||
2742 | return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); | ||
2743 | } | ||
2744 | |||
2745 | F32 LLWindowWin32::getPixelAspectRatio() | ||
2746 | { | ||
2747 | F32 pixel_aspect = 1.f; | ||
2748 | if (getFullscreen()) | ||
2749 | { | ||
2750 | LLCoordScreen screen_size; | ||
2751 | getSize(&screen_size); | ||
2752 | pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; | ||
2753 | } | ||
2754 | |||
2755 | return pixel_aspect; | ||
2756 | } | ||
2757 | |||
2758 | // Change display resolution. Returns true if successful. | ||
2759 | // protected | ||
2760 | BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) | ||
2761 | { | ||
2762 | DEVMODE dev_mode; | ||
2763 | dev_mode.dmSize = sizeof(dev_mode); | ||
2764 | BOOL success = FALSE; | ||
2765 | |||
2766 | // Don't change anything if we don't have to | ||
2767 | if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) | ||
2768 | { | ||
2769 | if (dev_mode.dmPelsWidth == width && | ||
2770 | dev_mode.dmPelsHeight == height && | ||
2771 | dev_mode.dmBitsPerPel == bits && | ||
2772 | dev_mode.dmDisplayFrequency == refresh ) | ||
2773 | { | ||
2774 | // ...display mode identical, do nothing | ||
2775 | return TRUE; | ||
2776 | } | ||
2777 | } | ||
2778 | |||
2779 | memset(&dev_mode, 0, sizeof(dev_mode)); | ||
2780 | dev_mode.dmSize = sizeof(dev_mode); | ||
2781 | dev_mode.dmPelsWidth = width; | ||
2782 | dev_mode.dmPelsHeight = height; | ||
2783 | dev_mode.dmBitsPerPel = bits; | ||
2784 | dev_mode.dmDisplayFrequency = refresh; | ||
2785 | dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; | ||
2786 | |||
2787 | // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. | ||
2788 | LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); | ||
2789 | |||
2790 | success = (DISP_CHANGE_SUCCESSFUL == cds_result); | ||
2791 | |||
2792 | if (!success) | ||
2793 | { | ||
2794 | llwarns << "setDisplayResolution failed, " | ||
2795 | << width << "x" << height << "x" << bits << " @ " << refresh << llendl; | ||
2796 | } | ||
2797 | |||
2798 | return success; | ||
2799 | } | ||
2800 | |||
2801 | // protected | ||
2802 | BOOL LLWindowWin32::setFullscreenResolution() | ||
2803 | { | ||
2804 | if (mFullscreen) | ||
2805 | { | ||
2806 | return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); | ||
2807 | } | ||
2808 | else | ||
2809 | { | ||
2810 | return FALSE; | ||
2811 | } | ||
2812 | } | ||
2813 | |||
2814 | // protected | ||
2815 | BOOL LLWindowWin32::resetDisplayResolution() | ||
2816 | { | ||
2817 | llinfos << "resetDisplayResolution START" << llendl; | ||
2818 | |||
2819 | LONG cds_result = ChangeDisplaySettings(NULL, 0); | ||
2820 | |||
2821 | BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); | ||
2822 | |||
2823 | if (!success) | ||
2824 | { | ||
2825 | llwarns << "resetDisplayResolution failed" << llendl; | ||
2826 | } | ||
2827 | |||
2828 | llinfos << "resetDisplayResolution END" << llendl; | ||
2829 | |||
2830 | return success; | ||
2831 | } | ||
2832 | |||
2833 | void LLWindowWin32::swapBuffers() | ||
2834 | { | ||
2835 | SwapBuffers(mhDC); | ||
2836 | } | ||
2837 | |||
2838 | |||
2839 | BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, | ||
2840 | VOID* pContext ) | ||
2841 | { | ||
2842 | HRESULT hr; | ||
2843 | |||
2844 | // Obtain an interface to the enumerated joystick. | ||
2845 | hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL ); | ||
2846 | |||
2847 | // If it failed, then we can't use this joystick. (Maybe the user unplugged | ||
2848 | // it while we were in the middle of enumerating it.) | ||
2849 | if( FAILED(hr) ) | ||
2850 | return DIENUM_CONTINUE; | ||
2851 | |||
2852 | // Stop enumeration. Note: we're just taking the first joystick we get. You | ||
2853 | // could store all the enumerated joysticks and let the user pick. | ||
2854 | return DIENUM_STOP; | ||
2855 | } | ||
2856 | |||
2857 | BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, | ||
2858 | VOID* pContext ) | ||
2859 | { | ||
2860 | if( pdidoi->dwType & DIDFT_AXIS ) | ||
2861 | { | ||
2862 | DIPROPRANGE diprg; | ||
2863 | diprg.diph.dwSize = sizeof(DIPROPRANGE); | ||
2864 | diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); | ||
2865 | diprg.diph.dwHow = DIPH_BYID; | ||
2866 | diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis | ||
2867 | diprg.lMin = -1000; | ||
2868 | diprg.lMax = +1000; | ||
2869 | |||
2870 | // Set the range for the axis | ||
2871 | if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) | ||
2872 | return DIENUM_STOP; | ||
2873 | |||
2874 | } | ||
2875 | return DIENUM_CONTINUE; | ||
2876 | } | ||
2877 | |||
2878 | void LLWindowWin32::updateJoystick( ) | ||
2879 | { | ||
2880 | HRESULT hr; | ||
2881 | DIJOYSTATE js; // DInput joystick state | ||
2882 | |||
2883 | if (!g_pJoystick) | ||
2884 | return; | ||
2885 | hr = g_pJoystick->Poll(); | ||
2886 | if ( hr == DIERR_INPUTLOST ) | ||
2887 | { | ||
2888 | hr = g_pJoystick->Acquire(); | ||
2889 | return; | ||
2890 | } | ||
2891 | else if ( FAILED(hr) ) | ||
2892 | return; | ||
2893 | |||
2894 | // Get the input's device state | ||
2895 | if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE), &js ) ) ) | ||
2896 | return; // The device should have been acquired during the Poll() | ||
2897 | |||
2898 | if (js.lX <= -500) | ||
2899 | { | ||
2900 | if (!(mJoyStickState & 0x1)) | ||
2901 | { | ||
2902 | gKeyboard->handleTranslatedKeyDown(KEY_PAD_LEFT, 0); | ||
2903 | mJoyStickState |= 0x1; | ||
2904 | } | ||
2905 | } | ||
2906 | else | ||
2907 | { | ||
2908 | if (mJoyStickState & 0x1) | ||
2909 | { | ||
2910 | gKeyboard->handleTranslatedKeyUp(KEY_PAD_LEFT, 0); | ||
2911 | mJoyStickState &= ~0x1; | ||
2912 | } | ||
2913 | } | ||
2914 | if (js.lX >= 500) | ||
2915 | { | ||
2916 | if (!(mJoyStickState & 0x2)) | ||
2917 | { | ||
2918 | gKeyboard->handleTranslatedKeyDown(KEY_PAD_RIGHT, 0); | ||
2919 | mJoyStickState |= 0x2; | ||
2920 | } | ||
2921 | } | ||
2922 | else | ||
2923 | { | ||
2924 | if (mJoyStickState & 0x2) | ||
2925 | { | ||
2926 | gKeyboard->handleTranslatedKeyUp(KEY_PAD_RIGHT, 0); | ||
2927 | mJoyStickState &= ~0x2; | ||
2928 | } | ||
2929 | } | ||
2930 | if (js.lY <= -500) | ||
2931 | { | ||
2932 | if (!(mJoyStickState & 0x4)) | ||
2933 | { | ||
2934 | gKeyboard->handleTranslatedKeyDown(KEY_PAD_UP, 0); | ||
2935 | mJoyStickState |= 0x4; | ||
2936 | } | ||
2937 | } | ||
2938 | else | ||
2939 | { | ||
2940 | if (mJoyStickState & 0x4) | ||
2941 | { | ||
2942 | gKeyboard->handleTranslatedKeyUp(KEY_PAD_UP, 0); | ||
2943 | mJoyStickState &= ~0x4; | ||
2944 | } | ||
2945 | } | ||
2946 | if (js.lY >= 500) | ||
2947 | { | ||
2948 | if (!(mJoyStickState & 0x8)) | ||
2949 | { | ||
2950 | gKeyboard->handleTranslatedKeyDown(KEY_PAD_DOWN, 0); | ||
2951 | mJoyStickState |= 0x8; | ||
2952 | } | ||
2953 | } | ||
2954 | else | ||
2955 | { | ||
2956 | if (mJoyStickState & 0x8) | ||
2957 | { | ||
2958 | gKeyboard->handleTranslatedKeyUp(KEY_PAD_DOWN, 0); | ||
2959 | mJoyStickState &= ~0x8; | ||
2960 | } | ||
2961 | } | ||
2962 | |||
2963 | for( int i = 0; i < 15; i++ ) | ||
2964 | { | ||
2965 | if ( js.rgbButtons[i] & 0x80 ) | ||
2966 | { | ||
2967 | if (!(mJoyButtonState & (1<<i))) | ||
2968 | { | ||
2969 | gKeyboard->handleTranslatedKeyDown(KEY_BUTTON1+i, 0); | ||
2970 | mJoyButtonState |= (1<<i); | ||
2971 | } | ||
2972 | } | ||
2973 | else | ||
2974 | { | ||
2975 | if (mJoyButtonState & (1<<i)) | ||
2976 | { | ||
2977 | gKeyboard->handleTranslatedKeyUp(KEY_BUTTON1+i, 0); | ||
2978 | mJoyButtonState &= ~(1<<i); | ||
2979 | } | ||
2980 | } | ||
2981 | } | ||
2982 | } | ||
2983 | |||
2984 | |||
2985 | // | ||
2986 | // LLSplashScreenImp | ||
2987 | // | ||
2988 | LLSplashScreenWin32::LLSplashScreenWin32() | ||
2989 | : mWindow(NULL) | ||
2990 | { | ||
2991 | } | ||
2992 | |||
2993 | LLSplashScreenWin32::~LLSplashScreenWin32() | ||
2994 | { | ||
2995 | } | ||
2996 | |||
2997 | void LLSplashScreenWin32::showImpl() | ||
2998 | { | ||
2999 | // This appears to work. ??? | ||
3000 | HINSTANCE hinst = GetModuleHandle(NULL); | ||
3001 | |||
3002 | mWindow = CreateDialog(hinst, | ||
3003 | TEXT("SPLASHSCREEN"), | ||
3004 | NULL, // no parent | ||
3005 | (DLGPROC) LLSplashScreenWin32::windowProc); | ||
3006 | ShowWindow(mWindow, SW_SHOW); | ||
3007 | } | ||
3008 | |||
3009 | |||
3010 | void LLSplashScreenWin32::updateImpl(const char *mesg) | ||
3011 | { | ||
3012 | if (!mWindow) return; | ||
3013 | |||
3014 | WCHAR w_mesg[1024]; | ||
3015 | mbstowcs(w_mesg, mesg, 1024); | ||
3016 | |||
3017 | SendDlgItemMessage(mWindow, | ||
3018 | 666, // HACK: text id | ||
3019 | WM_SETTEXT, | ||
3020 | FALSE, | ||
3021 | (LPARAM)w_mesg); | ||
3022 | } | ||
3023 | |||
3024 | |||
3025 | void LLSplashScreenWin32::hideImpl() | ||
3026 | { | ||
3027 | if (mWindow) | ||
3028 | { | ||
3029 | DestroyWindow(mWindow); | ||
3030 | mWindow = NULL; | ||
3031 | } | ||
3032 | } | ||
3033 | |||
3034 | |||
3035 | // static | ||
3036 | LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, | ||
3037 | WPARAM w_param, LPARAM l_param) | ||
3038 | { | ||
3039 | // Just give it to windows | ||
3040 | return DefWindowProc(h_wnd, u_msg, w_param, l_param); | ||
3041 | } | ||
3042 | |||
3043 | // | ||
3044 | // Helper Funcs | ||
3045 | // | ||
3046 | |||
3047 | S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type) | ||
3048 | { | ||
3049 | UINT uType; | ||
3050 | |||
3051 | switch(type) | ||
3052 | { | ||
3053 | case OSMB_OK: | ||
3054 | uType = MB_OK; | ||
3055 | break; | ||
3056 | case OSMB_OKCANCEL: | ||
3057 | uType = MB_OKCANCEL; | ||
3058 | break; | ||
3059 | case OSMB_YESNO: | ||
3060 | uType = MB_YESNO; | ||
3061 | break; | ||
3062 | default: | ||
3063 | uType = MB_OK; | ||
3064 | break; | ||
3065 | } | ||
3066 | |||
3067 | // HACK! Doesn't properly handle wide strings! | ||
3068 | int retval_win = MessageBoxA(NULL, text, caption, uType); | ||
3069 | S32 retval; | ||
3070 | |||
3071 | switch(retval_win) | ||
3072 | { | ||
3073 | case IDYES: | ||
3074 | retval = OSBTN_YES; | ||
3075 | break; | ||
3076 | case IDNO: | ||
3077 | retval = OSBTN_NO; | ||
3078 | break; | ||
3079 | case IDOK: | ||
3080 | retval = OSBTN_OK; | ||
3081 | break; | ||
3082 | case IDCANCEL: | ||
3083 | retval = OSBTN_CANCEL; | ||
3084 | break; | ||
3085 | default: | ||
3086 | retval = OSBTN_CANCEL; | ||
3087 | break; | ||
3088 | } | ||
3089 | |||
3090 | return retval; | ||
3091 | } | ||
3092 | |||
3093 | |||
3094 | void spawn_web_browser(const char* escaped_url ) | ||
3095 | { | ||
3096 | bool found = false; | ||
3097 | S32 i; | ||
3098 | for (i = 0; i < gURLProtocolWhitelistCount; i++) | ||
3099 | { | ||
3100 | S32 len = strlen(gURLProtocolWhitelist[i]); | ||
3101 | if (!strncmp(escaped_url, gURLProtocolWhitelist[i], len) | ||
3102 | && escaped_url[len] == ':') | ||
3103 | { | ||
3104 | found = true; | ||
3105 | break; | ||
3106 | } | ||
3107 | } | ||
3108 | |||
3109 | if (!found) | ||
3110 | { | ||
3111 | llwarns << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << llendl; | ||
3112 | return; | ||
3113 | } | ||
3114 | |||
3115 | llinfos << "Opening URL " << escaped_url << llendl; | ||
3116 | |||
3117 | // Figure out the user's default web browser | ||
3118 | // HKEY_CLASSES_ROOT\http\shell\open\command | ||
3119 | char reg_path_str[256]; | ||
3120 | sprintf(reg_path_str, "%s\\shell\\open\\command", gURLProtocolWhitelistHandler[i]); | ||
3121 | WCHAR reg_path_wstr[256]; | ||
3122 | mbstowcs(reg_path_wstr, reg_path_str, 1024); | ||
3123 | |||
3124 | HKEY key; | ||
3125 | WCHAR browser_open_wstr[1024]; | ||
3126 | DWORD buffer_length = 1024; | ||
3127 | RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key); | ||
3128 | RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length); | ||
3129 | RegCloseKey(key); | ||
3130 | |||
3131 | // Convert to STL string | ||
3132 | LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); | ||
3133 | |||
3134 | if (browser_open_wstring.length() < 2) | ||
3135 | { | ||
3136 | llwarns << "Invalid browser executable in registry " << browser_open_wstring << llendl; | ||
3137 | return; | ||
3138 | } | ||
3139 | |||
3140 | // Extract the process that's supposed to be launched | ||
3141 | LLWString browser_executable; | ||
3142 | if (browser_open_wstring[0] == '"') | ||
3143 | { | ||
3144 | // executable is quoted, find the matching quote | ||
3145 | size_t quote_pos = browser_open_wstring.find('"', 1); | ||
3146 | // copy out the string including both quotes | ||
3147 | browser_executable = browser_open_wstring.substr(0, quote_pos+1); | ||
3148 | } | ||
3149 | else | ||
3150 | { | ||
3151 | // executable not quoted, find a space | ||
3152 | size_t space_pos = browser_open_wstring.find(' ', 1); | ||
3153 | browser_executable = browser_open_wstring.substr(0, space_pos); | ||
3154 | } | ||
3155 | |||
3156 | llinfos << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << llendl; | ||
3157 | llinfos << "Browser executable: " << wstring_to_utf8str(browser_executable) << llendl; | ||
3158 | |||
3159 | // Convert URL to wide string for Windows API | ||
3160 | // Assume URL is UTF8, as can come from scripts | ||
3161 | LLWString url_wstring = utf8str_to_wstring(escaped_url); | ||
3162 | llutf16string url_utf16 = wstring_to_utf16str(url_wstring); | ||
3163 | |||
3164 | // Convert executable and path to wide string for Windows API | ||
3165 | llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); | ||
3166 | |||
3167 | // ShellExecute returns HINSTANCE for backwards compatiblity. | ||
3168 | // MS docs say to cast to int and compare to 32. | ||
3169 | HWND our_window = NULL; | ||
3170 | LPCWSTR directory_wstr = NULL; | ||
3171 | int retval = (int) ShellExecute(our_window, | ||
3172 | L"open", | ||
3173 | browser_exec_utf16.c_str(), | ||
3174 | url_utf16.c_str(), | ||
3175 | directory_wstr, | ||
3176 | SW_SHOWNORMAL); | ||
3177 | if (retval > 32) | ||
3178 | { | ||
3179 | llinfos << "load_url success with " << retval << llendl; | ||
3180 | } | ||
3181 | else | ||
3182 | { | ||
3183 | llinfos << "load_url failure with " << retval << llendl; | ||
3184 | } | ||
3185 | } | ||
3186 | |||
3187 | void shell_open( const char* file_path ) | ||
3188 | { | ||
3189 | llinfos << "Opening " << file_path << llendl; | ||
3190 | |||
3191 | WCHAR wstr[1024]; | ||
3192 | mbstowcs(wstr, file_path, 1024); | ||
3193 | |||
3194 | HWND our_window = NULL; | ||
3195 | int retval = (int) ShellExecute(our_window, L"open", wstr, NULL, NULL, SW_SHOWNORMAL); | ||
3196 | if (retval > 32) | ||
3197 | { | ||
3198 | llinfos << "ShellExecute success with " << retval << llendl; | ||
3199 | } | ||
3200 | else | ||
3201 | { | ||
3202 | llinfos << "ShellExecute failure with " << retval << llendl; | ||
3203 | } | ||
3204 | } | ||
3205 | |||
3206 | BOOL LLWindowWin32::dialog_color_picker ( F32 *r, F32 *g, F32 *b ) | ||
3207 | { | ||
3208 | BOOL retval = FALSE; | ||
3209 | |||
3210 | static CHOOSECOLOR cc; | ||
3211 | static COLORREF crCustColors[16]; | ||
3212 | cc.lStructSize = sizeof(CHOOSECOLOR); | ||
3213 | cc.hwndOwner = mWindowHandle; | ||
3214 | cc.hInstance = NULL; | ||
3215 | cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); | ||
3216 | //cc.rgbResult = RGB (0x80,0x80,0x80); | ||
3217 | cc.lpCustColors = crCustColors; | ||
3218 | cc.Flags = CC_RGBINIT | CC_FULLOPEN; | ||
3219 | cc.lCustData = 0; | ||
3220 | cc.lpfnHook = NULL; | ||
3221 | cc.lpTemplateName = NULL; | ||
3222 | |||
3223 | // This call is modal, so pause agent | ||
3224 | //send_agent_pause(); // this is in newview and we don't want to set up a dependency | ||
3225 | { | ||
3226 | retval = ChooseColor(&cc); | ||
3227 | } | ||
3228 | //send_agent_resume(); // this is in newview and we don't want to set up a dependency | ||
3229 | |||
3230 | *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; | ||
3231 | |||
3232 | *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; | ||
3233 | |||
3234 | *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; | ||
3235 | |||
3236 | return (retval); | ||
3237 | } | ||
3238 | |||
3239 | void *LLWindowWin32::getPlatformWindow() | ||
3240 | { | ||
3241 | return (void*)mWindowHandle; | ||
3242 | } | ||
3243 | |||
3244 | void LLWindowWin32::bringToFront() | ||
3245 | { | ||
3246 | BringWindowToTop(mWindowHandle); | ||
3247 | } | ||
3248 | |||
3249 | // set (OS) window focus back to the client | ||
3250 | void LLWindowWin32::focusClient() | ||
3251 | { | ||
3252 | SetFocus ( mWindowHandle ); | ||
3253 | }; | ||
3254 | |||
3255 | #endif // LL_WINDOWS | ||
diff --git a/linden/indra/llwindow/llwindowwin32.h b/linden/indra/llwindow/llwindowwin32.h new file mode 100644 index 0000000..77696e6 --- /dev/null +++ b/linden/indra/llwindow/llwindowwin32.h | |||
@@ -0,0 +1,209 @@ | |||
1 | /** | ||
2 | * @file llwindowwin32.h | ||
3 | * @brief Windows implementation of LLWindow class | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #ifndef LL_LLWINDOWWIN32_H | ||
29 | #define LL_LLWINDOWWIN32_H | ||
30 | |||
31 | // Limit Windows API to small and manageable set. | ||
32 | #define WIN32_LEAN_AND_MEAN | ||
33 | #include <winsock2.h> | ||
34 | #include <windows.h> | ||
35 | |||
36 | #include "llwindow.h" | ||
37 | |||
38 | // Hack for async host by name | ||
39 | #define LL_WM_HOST_RESOLVED (WM_APP + 1) | ||
40 | typedef void (*LLW32MsgCallback)(const MSG &msg); | ||
41 | |||
42 | class LLWindowWin32 : public LLWindow | ||
43 | { | ||
44 | public: | ||
45 | /*virtual*/ void show(); | ||
46 | /*virtual*/ void hide(); | ||
47 | /*virtual*/ void close(); | ||
48 | /*virtual*/ BOOL getVisible(); | ||
49 | /*virtual*/ BOOL getMinimized(); | ||
50 | /*virtual*/ BOOL getMaximized(); | ||
51 | /*virtual*/ BOOL maximize(); | ||
52 | /*virtual*/ BOOL getFullscreen(); | ||
53 | /*virtual*/ BOOL getPosition(LLCoordScreen *position); | ||
54 | /*virtual*/ BOOL getSize(LLCoordScreen *size); | ||
55 | /*virtual*/ BOOL getSize(LLCoordWindow *size); | ||
56 | /*virtual*/ BOOL setPosition(LLCoordScreen position); | ||
57 | /*virtual*/ BOOL setSize(LLCoordScreen size); | ||
58 | /*virtual*/ BOOL switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync); | ||
59 | /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); | ||
60 | /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); | ||
61 | /*virtual*/ void showCursor(); | ||
62 | /*virtual*/ void hideCursor(); | ||
63 | /*virtual*/ void showCursorFromMouseMove(); | ||
64 | /*virtual*/ void hideCursorUntilMouseMove(); | ||
65 | /*virtual*/ BOOL isCursorHidden(); | ||
66 | /*virtual*/ void setCursor(ECursorType cursor); | ||
67 | /*virtual*/ ECursorType getCursor(); | ||
68 | /*virtual*/ void captureMouse(); | ||
69 | /*virtual*/ void releaseMouse(); | ||
70 | /*virtual*/ void setMouseClipping( BOOL b ); | ||
71 | /*virtual*/ BOOL isClipboardTextAvailable(); | ||
72 | /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); | ||
73 | /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); | ||
74 | /*virtual*/ void flashIcon(F32 seconds); | ||
75 | /*virtual*/ F32 getGamma(); | ||
76 | /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma | ||
77 | /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) | ||
78 | /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } | ||
79 | /*virtual*/ void gatherInput(); | ||
80 | /*virtual*/ void delayInputProcessing(); | ||
81 | /*virtual*/ void swapBuffers(); | ||
82 | |||
83 | /*virtual*/ LLString getTempFileName(); | ||
84 | /*virtual*/ void deleteFile( const char* file_name ); | ||
85 | /*virtual*/ S32 stat( const char* file_name, struct stat* stat_info ); | ||
86 | /*virtual*/ BOOL sendEmail(const char* address,const char* subject,const char* body_text,const char* attachment=NULL, const char* attachment_displayed_name=NULL); | ||
87 | |||
88 | |||
89 | // handy coordinate space conversion routines | ||
90 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); | ||
91 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); | ||
92 | /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); | ||
93 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); | ||
94 | /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); | ||
95 | /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); | ||
96 | |||
97 | /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); | ||
98 | /*virtual*/ F32 getNativeAspectRatio(); | ||
99 | /*virtual*/ F32 getPixelAspectRatio(); | ||
100 | /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } | ||
101 | |||
102 | /*virtual*/ BOOL dialog_color_picker (F32 *r, F32 *g, F32 *b ); | ||
103 | |||
104 | /*virtual*/ void *getPlatformWindow(); | ||
105 | /*virtual*/ void bringToFront(); | ||
106 | /*virtual*/ void focusClient(); | ||
107 | |||
108 | protected: | ||
109 | LLWindowWin32( | ||
110 | char *title, char *name, int x, int y, int width, int height, U32 flags, | ||
111 | BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, | ||
112 | BOOL ignore_pixel_depth); | ||
113 | ~LLWindowWin32(); | ||
114 | |||
115 | void initCursors(); | ||
116 | HCURSOR loadColorCursor(LPCTSTR name); | ||
117 | BOOL isValid(); | ||
118 | void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); | ||
119 | |||
120 | |||
121 | // Changes display resolution. Returns true if successful | ||
122 | BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); | ||
123 | |||
124 | // Go back to last fullscreen display resolution. | ||
125 | BOOL setFullscreenResolution(); | ||
126 | |||
127 | // Restore the display resolution to its value before we ran the app. | ||
128 | BOOL resetDisplayResolution(); | ||
129 | |||
130 | void minimize(); | ||
131 | void restore(); | ||
132 | |||
133 | BOOL shouldPostQuit() { return mPostQuit; } | ||
134 | |||
135 | |||
136 | protected: | ||
137 | // | ||
138 | // Platform specific methods | ||
139 | // | ||
140 | |||
141 | BOOL getClientRectInScreenSpace(RECT* rectp); | ||
142 | void updateJoystick( ); | ||
143 | |||
144 | static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); | ||
145 | static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); | ||
146 | |||
147 | |||
148 | // | ||
149 | // Platform specific variables | ||
150 | // | ||
151 | WCHAR *mWindowTitle; | ||
152 | WCHAR *mWindowClassName; | ||
153 | |||
154 | HWND mWindowHandle; // window handle | ||
155 | HGLRC mhRC; // OpenGL rendering context | ||
156 | HDC mhDC; // Windows Device context handle | ||
157 | HINSTANCE mhInstance; // handle to application instance | ||
158 | WNDPROC mWndProc; // user-installable window proc | ||
159 | RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() | ||
160 | WPARAM mLastSizeWParam; | ||
161 | F32 mOverrideAspectRatio; | ||
162 | F32 mNativeAspectRatio; | ||
163 | |||
164 | HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors | ||
165 | |||
166 | static BOOL sIsClassRegistered; // has the window class been registered? | ||
167 | |||
168 | F32 mCurrentGamma; | ||
169 | WORD mPrevGammaRamp[256*3]; | ||
170 | WORD mCurrentGammaRamp[256*3]; | ||
171 | |||
172 | U32 mJoyStickState; | ||
173 | U32 mJoyButtonState; | ||
174 | |||
175 | LPWSTR mIconResource; | ||
176 | BOOL mMousePositionModified; | ||
177 | BOOL mInputProcessingPaused; | ||
178 | |||
179 | friend class LLWindowManager; | ||
180 | }; | ||
181 | |||
182 | class LLSplashScreenWin32 : public LLSplashScreen | ||
183 | { | ||
184 | public: | ||
185 | LLSplashScreenWin32(); | ||
186 | virtual ~LLSplashScreenWin32(); | ||
187 | |||
188 | /*virtual*/ void showImpl(); | ||
189 | /*virtual*/ void updateImpl(const char* mesg); | ||
190 | /*virtual*/ void hideImpl(); | ||
191 | |||
192 | #if LL_WINDOWS | ||
193 | static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, | ||
194 | WPARAM w_param, LPARAM l_param); | ||
195 | #endif | ||
196 | |||
197 | private: | ||
198 | #if LL_WINDOWS | ||
199 | HWND mWindow; | ||
200 | #endif | ||
201 | }; | ||
202 | |||
203 | extern LLW32MsgCallback gAsyncMsgCallback; | ||
204 | |||
205 | static void handleMessage( const MSG& msg ); | ||
206 | |||
207 | S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type); | ||
208 | |||
209 | #endif //LL_LLWINDOWWIN32_H | ||