aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llwindow
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llwindow
parentREADME.txt (diff)
downloadmeta-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 '')
-rw-r--r--linden/indra/llwindow/files.darwin.lst2
-rw-r--r--linden/indra/llwindow/files.linux.lst4
-rw-r--r--linden/indra/llwindow/files.lst5
-rw-r--r--linden/indra/llwindow/lldxhardware.cpp527
-rw-r--r--linden/indra/llwindow/lldxhardware.h109
-rw-r--r--linden/indra/llwindow/llgl.cpp1378
-rw-r--r--linden/indra/llwindow/llgl.h272
-rw-r--r--linden/indra/llwindow/llglheaders.h486
-rw-r--r--linden/indra/llwindow/llglstates.h339
-rw-r--r--linden/indra/llwindow/llglstubs.h232
-rw-r--r--linden/indra/llwindow/llgltypes.h40
-rw-r--r--linden/indra/llwindow/llkeyboard.cpp392
-rw-r--r--linden/indra/llwindow/llkeyboard.h144
-rw-r--r--linden/indra/llwindow/llkeyboardmacosx.cpp328
-rw-r--r--linden/indra/llwindow/llkeyboardmacosx.h55
-rw-r--r--linden/indra/llwindow/llkeyboardsdl.cpp343
-rw-r--r--linden/indra/llwindow/llkeyboardsdl.h56
-rw-r--r--linden/indra/llwindow/llkeyboardwin32.cpp401
-rw-r--r--linden/indra/llwindow/llkeyboardwin32.h59
-rw-r--r--linden/indra/llwindow/llmousehandler.h58
-rw-r--r--linden/indra/llwindow/llwindow.cpp420
-rw-r--r--linden/indra/llwindow/llwindow.h334
-rw-r--r--linden/indra/llwindow/llwindow.vcproj270
-rw-r--r--linden/indra/llwindow/llwindowheadless.cpp51
-rw-r--r--linden/indra/llwindow/llwindowheadless.h117
-rw-r--r--linden/indra/llwindow/llwindowlinux.cpp57
-rw-r--r--linden/indra/llwindow/llwindowlinux.h115
-rw-r--r--linden/indra/llwindow/llwindowmacosx-objc.h38
-rw-r--r--linden/indra/llwindow/llwindowmacosx-objc.mm106
-rw-r--r--linden/indra/llwindow/llwindowmacosx.cpp2923
-rw-r--r--linden/indra/llwindow/llwindowmacosx.h208
-rw-r--r--linden/indra/llwindow/llwindowmesaheadless.cpp83
-rw-r--r--linden/indra/llwindow/llwindowmesaheadless.h123
-rw-r--r--linden/indra/llwindow/llwindowsdl.cpp2506
-rw-r--r--linden/indra/llwindow/llwindowsdl.h217
-rw-r--r--linden/indra/llwindow/llwindowwin32.cpp3255
-rw-r--r--linden/indra/llwindow/llwindowwin32.h209
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 @@
1llwindow/llkeyboardmacosx.cpp
2llwindow/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 @@
1llwindow/llkeyboardsdl.cpp
2llwindow/llwindowsdl.cpp
3llwindow/llwindowlinux.cpp
4llwindow/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 @@
1llwindow/lldxhardware.cpp
2llwindow/llgl.cpp
3llwindow/llkeyboard.cpp
4llwindow/llwindow.cpp
5llwindow/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
45void (*gWriteDebug)(const char* msg) = NULL;
46LLDXHardware 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
55std::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
90LLVersion::LLVersion()
91{
92 mValid = FALSE;
93 S32 i;
94 for (i = 0; i < 4; i++)
95 {
96 mFields[i] = 0;
97 }
98}
99
100BOOL 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
136S32 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
148LLString 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
170LLDXDevice::~LLDXDevice()
171{
172 for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer());
173}
174
175std::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
207LLDXDriverFile *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
223LLDXHardware::LLDXHardware()
224{
225 mVRAM = 0;
226 gWriteDebug = NULL;
227}
228
229void LLDXHardware::cleanup()
230{
231 for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer());
232}
233
234LLString 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
255LLDXDevice *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
283BOOL 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
503LCleanup:
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
522void 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
36class LLVersion
37{
38public:
39 LLVersion();
40 BOOL set(const std::string &version_string);
41 S32 getField(const S32 field_num);
42protected:
43 std::string mVersionString;
44 S32 mFields[4];
45 BOOL mValid;
46};
47
48class LLDXDriverFile
49{
50public:
51 LLString dump();
52
53public:
54 std::string mFilepath;
55 std::string mName;
56 std::string mVersionString;
57 LLVersion mVersion;
58 std::string mDateString;
59};
60
61class LLDXDevice
62{
63public:
64 ~LLDXDevice();
65 std::string dump();
66
67 LLDXDriverFile *findDriver(const std::string &driver);
68public:
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
79class LLDXHardware
80{
81public:
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();
99public:
100 typedef std::map<std::string, LLDXDevice *> device_map_t;
101 device_map_t mDevices;
102protected:
103 S32 mVRAM;
104};
105
106extern void (*gWriteDebug)(const char* msg);
107extern 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
72BOOL gClothRipple = FALSE;
73BOOL gNoRender = FALSE;
74
75
76#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS
77// ATI prototypes
78// vertex blending prototypes
79PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB = NULL;
80PFNGLVERTEXBLENDARBPROC glVertexBlendARB = NULL;
81PFNGLWEIGHTFVARBPROC glWeightfvARB = NULL;
82
83// Vertex buffer object prototypes
84PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;
85PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL;
86PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;
87PFNGLISBUFFERARBPROC glIsBufferARB = NULL;
88PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL;
89PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB = NULL;
90PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB = NULL;
91PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
92PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
93PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB = NULL;
94PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB = NULL;
95
96// vertex object prototypes
97PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL;
98PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL;
99PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI = NULL;
100PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI = NULL;
101PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI = NULL;
102PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI = NULL;
103PFNGLARRAYOBJECTATIPROC glArrayObjectATI = NULL;
104PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI = NULL;
105PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI = NULL;
106PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI = NULL;
107PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI = NULL;
108PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI = NULL;
109PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI = NULL;
110
111// GL_ARB_occlusion_query
112PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL;
113PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL;
114PFNGLISQUERYARBPROC glIsQueryARB = NULL;
115PFNGLBEGINQUERYARBPROC glBeginQueryARB = NULL;
116PFNGLENDQUERYARBPROC glEndQueryARB = NULL;
117PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
118PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
119PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
120
121//shader object prototypes
122PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
123PFNGLGETHANDLEARBPROC glGetHandleARB = NULL;
124PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
125PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
126PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
127PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
128PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
129PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
130PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
131PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
132PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB = NULL;
133PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
134PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
135PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
136PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
137PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
138PFNGLUNIFORM2IARBPROC glUniform2iARB = NULL;
139PFNGLUNIFORM3IARBPROC glUniform3iARB = NULL;
140PFNGLUNIFORM4IARBPROC glUniform4iARB = NULL;
141PFNGLUNIFORM1FVARBPROC glUniform1fvARB = NULL;
142PFNGLUNIFORM2FVARBPROC glUniform2fvARB = NULL;
143PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
144PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL;
145PFNGLUNIFORM1IVARBPROC glUniform1ivARB = NULL;
146PFNGLUNIFORM2IVARBPROC glUniform2ivARB = NULL;
147PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL;
148PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL;
149PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB = NULL;
150PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB = NULL;
151PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB = NULL;
152PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB = NULL;
153PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
154PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
155PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB = NULL;
156PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
157PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB = NULL;
158PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB = NULL;
159PFNGLGETUNIFORMIVARBPROC glGetUniformivARB = NULL;
160PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB = NULL;
161
162// vertex shader prototypes
163#if LL_LINUX
164PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB = NULL;
165PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB = NULL;
166PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
167PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB = NULL;
168PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB = NULL;
169PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB = NULL;
170PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB = NULL;
171PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB = NULL;
172PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB = NULL;
173PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB = NULL;
174PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB = NULL;
175PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB = NULL;
176PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB = NULL;
177PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB = NULL;
178PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB = NULL;
179PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB = NULL;
180PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB = NULL;
181PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB = NULL;
182#endif // LL_LINUX
183PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB = NULL;
184PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB = NULL;
185PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB = NULL;
186PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB = NULL;
187PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB = NULL;
188PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB = NULL;
189PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB = NULL;
190#if LL_LINUX
191PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB = NULL;
192PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB = NULL;
193PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB = NULL;
194PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB = NULL;
195PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB = NULL;
196PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB = NULL;
197PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB = NULL;
198PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB = NULL;
199PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB = NULL;
200PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB = NULL;
201PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB = NULL;
202PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB = NULL;
203PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB = NULL;
204PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB = NULL;
205PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL;
206PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL;
207PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL;
208PFNGLGENPROGRAMSARBPROC glGenProgramsARB = NULL;
209PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB = NULL;
210PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB = NULL;
211PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL;
212PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL;
213PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB = NULL;
214PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB = NULL;
215PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL;
216PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL;
217PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB = NULL;
218PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL;
219PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB = NULL;
220PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL;
221PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL;
222PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL;
223PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB = NULL;
224PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB = NULL;
225PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB = NULL;
226PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB = NULL;
227PFNGLISPROGRAMARBPROC glIsProgramARB = NULL;
228#endif // LL_LINUX
229PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB = NULL;
230PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL;
231PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
232
233#if LL_WINDOWS
234PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
235#endif
236
237#if LL_LINUX
238PFNGLCOLORTABLEEXTPROC glColorTableEXT = NULL;
239#endif // LL_LINUX
240
241#endif
242
243LLGLManager gGLManager;
244
245LLGLManager::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//---------------------------------------------------------------------
299void 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
331bool 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
459LLString 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
477LLString 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
486void 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
498extern LLCPUInfo gSysCPU;
499
500void 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
909void 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
916void flush_glerror()
917{
918 glGetError();
919}
920
921void 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
942void 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
956std::map<LLGLenum, LLGLboolean> LLGLState::sStateMap;
957
958GLboolean LLGLDepthTest::sDepthEnabled = GL_FALSE; // OpenGL default
959GLenum LLGLDepthTest::sDepthFunc = GL_LESS; // OpenGL default
960GLboolean LLGLDepthTest::sWriteEnabled = GL_TRUE; // OpenGL default
961
962//static
963void LLGLState::initClass()
964{
965 sStateMap[GL_DITHER] = GL_TRUE;
966}
967
968//static
969void LLGLState::restoreGL()
970{
971 sStateMap.clear();
972 initClass();
973}
974
975void 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
985void 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
1023void 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
1107void 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
1145LLGLState::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
1158void 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
1181LLGLState::~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
1209void LLGLManager::initGLStates()
1210{
1211 //gl states moved to classes in llglstates.h
1212 LLGLState::initClass();
1213}
1214
1215//============================================================================
1216
1217void 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
1224void 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
1231void 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
1241void 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
1252void enable_cloth_weights(const S32 index)
1253{
1254#if GL_ARB_vertex_program
1255 if (index > 0) glEnableVertexAttribArrayARB(index);
1256#endif
1257}
1258
1259void disable_cloth_weights(const S32 index)
1260{
1261#if GL_ARB_vertex_program
1262 if (index > 0) glDisableVertexAttribArrayARB(index);
1263#endif
1264}
1265
1266void 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
1274void 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
1282void 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
1291void 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
1300void 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...
46class LLGLManager
47{
48public:
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
132private:
133 void initExtensions();
134 void initGLStates();
135 void initGLImages();
136};
137
138extern LLGLManager gGLManager;
139
140class LLQuaternion;
141class LLMatrix4;
142
143void rotate_quat(LLQuaternion& rotation);
144
145void flush_glerror(); // Flush GL errors when we know we're handling them correctly.
146
147void assert_glerror();
148
149void 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*/
216class LLGLState
217{
218public:
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
227protected:
228 static std::map<LLGLenum, LLGLboolean> sStateMap;
229
230public:
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); }
237protected:
238 LLGLenum mState;
239 BOOL mWasEnabled;
240 BOOL mIsEnabled;
241};
242
243class LLGLEnable : public LLGLState
244{
245public:
246 LLGLEnable(LLGLenum state) : LLGLState(state, TRUE) {}
247};
248
249class LLGLDisable : public LLGLState
250{
251public:
252 LLGLDisable(LLGLenum state) : LLGLState(state, FALSE) {}
253};
254
255#include "llglstates.h"
256
257void init_glstates();
258void enable_vertex_weighting(const S32 index);
259void disable_vertex_weighting(const S32 index);
260void enable_binormals(const S32 index);
261void disable_binormals(const S32 index);
262void enable_cloth_weights(const S32 index);
263void disable_cloth_weights(const S32 index);
264void set_vertex_weights(const S32 index, const F32 *weights);
265void set_vertex_clothing_weights(const S32 index, const U32 stride, const LLVector4 *weights);
266void set_binormals(const S32 index, const U32 stride, const LLVector3 *binormals);
267void set_palette(U8* palette_data);
268void parse_gl_version( S32* major, S32* minor, S32* release, LLString* vendor_specific );
269
270extern BOOL gClothRipple;
271extern 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
58extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
59extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
60extern PFNGLGENBUFFERSARBPROC glGenBuffersARB;
61extern PFNGLISBUFFERARBPROC glIsBufferARB;
62extern PFNGLBUFFERDATAARBPROC glBufferDataARB;
63extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB;
64extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB;
65extern PFNGLMAPBUFFERARBPROC glMapBufferARB;
66extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
67extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
68extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
69
70// GL_ATI_vertex_array_object
71extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
72extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
73extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI;
74extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI;
75extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI;
76extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI;
77extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI;
78extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI;
79extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI;
80extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI;
81extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI;
82extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI;
83extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI;
84
85// GL_ARB_occlusion_query
86extern PFNGLGENQUERIESARBPROC glGenQueriesARB;
87extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB;
88extern PFNGLISQUERYARBPROC glIsQueryARB;
89extern PFNGLBEGINQUERYARBPROC glBeginQueryARB;
90extern PFNGLENDQUERYARBPROC glEndQueryARB;
91extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
92extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
93extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
94
95// GL_ARB_shader_objects
96extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
97extern PFNGLGETHANDLEARBPROC glGetHandleARB;
98extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB;
99extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
100extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
101extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
102extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
103extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
104extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
105extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
106extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB;
107extern PFNGLUNIFORM1FARBPROC glUniform1fARB;
108extern PFNGLUNIFORM2FARBPROC glUniform2fARB;
109extern PFNGLUNIFORM3FARBPROC glUniform3fARB;
110extern PFNGLUNIFORM4FARBPROC glUniform4fARB;
111extern PFNGLUNIFORM1IARBPROC glUniform1iARB;
112extern PFNGLUNIFORM2IARBPROC glUniform2iARB;
113extern PFNGLUNIFORM3IARBPROC glUniform3iARB;
114extern PFNGLUNIFORM4IARBPROC glUniform4iARB;
115extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB;
116extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB;
117extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB;
118extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB;
119extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB;
120extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB;
121extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB;
122extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB;
123extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB;
124extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB;
125extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB;
126extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB;
127extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
128extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
129extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB;
130extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
131extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB;
132extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB;
133extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB;
134extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB;
135
136// GL_ARB;_vertex_shader
137extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB;
138extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB;
139extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB;
140extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB;
141extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB;
142extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB;
143extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB;
144extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB;
145extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB;
146extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB;
147extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB;
148extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB;
149extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB;
150extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB;
151extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB;
152extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB;
153extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB;
154extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB;
155extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB;
156extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB;
157extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB;
158extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB;
159extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB;
160extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB;
161extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB;
162extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB;
163extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB;
164extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB;
165extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB;
166extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB;
167extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB;
168extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB;
169extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB;
170extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
171extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
172extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
173extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
174extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
175extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
176extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
177extern PFNGLBINDPROGRAMARBPROC glBindProgramARB;
178extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
179extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
180extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB;
181extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB;
182extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
183extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB;
184extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB;
185extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB;
186extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
187extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
188extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB;
189extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB;
190extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB;
191extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB;
192extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
193extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
194extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB;
195extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB;
196extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB;
197extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB;
198extern PFNGLISPROGRAMARBPROC glIsProgramARB;
199extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
200extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
201extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
202
203extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;
204extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
205
206extern 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
219extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
220extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
221extern PFNGLGENBUFFERSARBPROC glGenBuffersARB;
222extern PFNGLISBUFFERARBPROC glIsBufferARB;
223extern PFNGLBUFFERDATAARBPROC glBufferDataARB;
224extern PFNGLBUFFERSUBDATAARBPROC glBufferSubDataARB;
225extern PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubDataARB;
226extern PFNGLMAPBUFFERARBPROC glMapBufferARB;
227extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
228extern PFNGLGETBUFFERPARAMETERIVARBPROC glGetBufferParameterivARB;
229extern PFNGLGETBUFFERPOINTERVARBPROC glGetBufferPointervARB;
230
231// GL_ATI_vertex_array_object
232extern PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI;
233extern PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI;
234extern PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI;
235extern PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI;
236extern PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI;
237extern PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI;
238extern PFNGLARRAYOBJECTATIPROC glArrayObjectATI;
239extern PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI;
240extern PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI;
241extern PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI;
242extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI;
243extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI;
244extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI;
245
246extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
247
248// GL_ARB_occlusion_query
249extern PFNGLGENQUERIESARBPROC glGenQueriesARB;
250extern PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB;
251extern PFNGLISQUERYARBPROC glIsQueryARB;
252extern PFNGLBEGINQUERYARBPROC glBeginQueryARB;
253extern PFNGLENDQUERYARBPROC glEndQueryARB;
254extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
255extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
256extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
257
258// GL_ARB_shader_objects
259extern PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
260extern PFNGLGETHANDLEARBPROC glGetHandleARB;
261extern PFNGLDETACHOBJECTARBPROC glDetachObjectARB;
262extern PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
263extern PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
264extern PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
265extern PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
266extern PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
267extern PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
268extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
269extern PFNGLVALIDATEPROGRAMARBPROC glValidateProgramARB;
270extern PFNGLUNIFORM1FARBPROC glUniform1fARB;
271extern PFNGLUNIFORM2FARBPROC glUniform2fARB;
272extern PFNGLUNIFORM3FARBPROC glUniform3fARB;
273extern PFNGLUNIFORM4FARBPROC glUniform4fARB;
274extern PFNGLUNIFORM1IARBPROC glUniform1iARB;
275extern PFNGLUNIFORM2IARBPROC glUniform2iARB;
276extern PFNGLUNIFORM3IARBPROC glUniform3iARB;
277extern PFNGLUNIFORM4IARBPROC glUniform4iARB;
278extern PFNGLUNIFORM1FVARBPROC glUniform1fvARB;
279extern PFNGLUNIFORM2FVARBPROC glUniform2fvARB;
280extern PFNGLUNIFORM3FVARBPROC glUniform3fvARB;
281extern PFNGLUNIFORM4FVARBPROC glUniform4fvARB;
282extern PFNGLUNIFORM1IVARBPROC glUniform1ivARB;
283extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB;
284extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB;
285extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB;
286extern PFNGLUNIFORMMATRIX2FVARBPROC glUniformMatrix2fvARB;
287extern PFNGLUNIFORMMATRIX3FVARBPROC glUniformMatrix3fvARB;
288extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fvARB;
289extern PFNGLGETOBJECTPARAMETERFVARBPROC glGetObjectParameterfvARB;
290extern PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
291extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
292extern PFNGLGETATTACHEDOBJECTSARBPROC glGetAttachedObjectsARB;
293extern PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
294extern PFNGLGETACTIVEUNIFORMARBPROC glGetActiveUniformARB;
295extern PFNGLGETUNIFORMFVARBPROC glGetUniformfvARB;
296extern PFNGLGETUNIFORMIVARBPROC glGetUniformivARB;
297extern PFNGLGETSHADERSOURCEARBPROC glGetShaderSourceARB;
298
299// GL_ARB;_vertex_shader
300extern PFNGLVERTEXATTRIB1DARBPROC glVertexAttrib1dARB;
301extern PFNGLVERTEXATTRIB1DVARBPROC glVertexAttrib1dvARB;
302extern PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB;
303extern PFNGLVERTEXATTRIB1FVARBPROC glVertexAttrib1fvARB;
304extern PFNGLVERTEXATTRIB1SARBPROC glVertexAttrib1sARB;
305extern PFNGLVERTEXATTRIB1SVARBPROC glVertexAttrib1svARB;
306extern PFNGLVERTEXATTRIB2DARBPROC glVertexAttrib2dARB;
307extern PFNGLVERTEXATTRIB2DVARBPROC glVertexAttrib2dvARB;
308extern PFNGLVERTEXATTRIB2FARBPROC glVertexAttrib2fARB;
309extern PFNGLVERTEXATTRIB2FVARBPROC glVertexAttrib2fvARB;
310extern PFNGLVERTEXATTRIB2SARBPROC glVertexAttrib2sARB;
311extern PFNGLVERTEXATTRIB2SVARBPROC glVertexAttrib2svARB;
312extern PFNGLVERTEXATTRIB3DARBPROC glVertexAttrib3dARB;
313extern PFNGLVERTEXATTRIB3DVARBPROC glVertexAttrib3dvARB;
314extern PFNGLVERTEXATTRIB3FARBPROC glVertexAttrib3fARB;
315extern PFNGLVERTEXATTRIB3FVARBPROC glVertexAttrib3fvARB;
316extern PFNGLVERTEXATTRIB3SARBPROC glVertexAttrib3sARB;
317extern PFNGLVERTEXATTRIB3SVARBPROC glVertexAttrib3svARB;
318extern PFNGLVERTEXATTRIB4NBVARBPROC glVertexAttrib4nbvARB;
319extern PFNGLVERTEXATTRIB4NIVARBPROC glVertexAttrib4nivARB;
320extern PFNGLVERTEXATTRIB4NSVARBPROC glVertexAttrib4nsvARB;
321extern PFNGLVERTEXATTRIB4NUBARBPROC glVertexAttrib4nubARB;
322extern PFNGLVERTEXATTRIB4NUBVARBPROC glVertexAttrib4nubvARB;
323extern PFNGLVERTEXATTRIB4NUIVARBPROC glVertexAttrib4nuivARB;
324extern PFNGLVERTEXATTRIB4NUSVARBPROC glVertexAttrib4nusvARB;
325extern PFNGLVERTEXATTRIB4BVARBPROC glVertexAttrib4bvARB;
326extern PFNGLVERTEXATTRIB4DARBPROC glVertexAttrib4dARB;
327extern PFNGLVERTEXATTRIB4DVARBPROC glVertexAttrib4dvARB;
328extern PFNGLVERTEXATTRIB4FARBPROC glVertexAttrib4fARB;
329extern PFNGLVERTEXATTRIB4FVARBPROC glVertexAttrib4fvARB;
330extern PFNGLVERTEXATTRIB4IVARBPROC glVertexAttrib4ivARB;
331extern PFNGLVERTEXATTRIB4SARBPROC glVertexAttrib4sARB;
332extern PFNGLVERTEXATTRIB4SVARBPROC glVertexAttrib4svARB;
333extern PFNGLVERTEXATTRIB4UBVARBPROC glVertexAttrib4ubvARB;
334extern PFNGLVERTEXATTRIB4UIVARBPROC glVertexAttrib4uivARB;
335extern PFNGLVERTEXATTRIB4USVARBPROC glVertexAttrib4usvARB;
336extern PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointerARB;
337extern PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArrayARB;
338extern PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArrayARB;
339extern PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
340extern PFNGLBINDPROGRAMARBPROC glBindProgramARB;
341extern PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
342extern PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
343extern PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB;
344extern PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB;
345extern PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB;
346extern PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB;
347extern PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB;
348extern PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB;
349extern PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB;
350extern PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB;
351extern PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB;
352extern PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB;
353extern PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB;
354extern PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB;
355extern PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
356extern PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
357extern PFNGLGETVERTEXATTRIBDVARBPROC glGetVertexAttribdvARB;
358extern PFNGLGETVERTEXATTRIBFVARBPROC glGetVertexAttribfvARB;
359extern PFNGLGETVERTEXATTRIBIVARBPROC glGetVertexAttribivARB;
360extern PFNGLGETVERTEXATTRIBPOINTERVARBPROC glGetVertexAttribPointervARB;
361extern PFNGLISPROGRAMARBPROC glIsProgramARB;
362extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
363extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
364extern 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
380extern "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 */
423typedef intptr_t GLintptrARB;
424typedef 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
431typedef void (* glBindBufferARBProcPtr) (GLenum target, GLuint buffer);
432typedef void (* glDeleteBufferARBProcPtr) (GLsizei n, const GLuint *buffers);
433typedef void (* glGenBuffersARBProcPtr) (GLsizei n, GLuint *buffers);
434typedef GLboolean (* glIsBufferARBProcPtr) (GLuint buffer);
435typedef void (* glBufferDataARBProcPtr) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage);
436typedef void (* glBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data);
437typedef void (* glGetBufferSubDataARBProcPtr) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data);
438typedef GLvoid* (* glMapBufferARBProcPtr) (GLenum target, GLenum access);
439typedef GLboolean (* glUnmapBufferARBProcPtr) (GLenum target);
440typedef void (* glGetBufferParameterivARBProcPtr) (GLenum target, GLenum pname, GLint *params);
441typedef void (* glGetBufferPointervARBProcPtr) (GLenum target, GLenum pname, GLvoid* *params);
442#else
443extern void glBindBufferARB (GLenum, GLuint);
444extern void glDeleteBuffersARB (GLsizei, const GLuint *);
445extern void glGenBuffersARB (GLsizei, GLuint *);
446extern GLboolean glIsBufferARB (GLuint);
447extern void glBufferDataARB (GLenum, GLsizeiptrARB, const GLvoid *, GLenum);
448extern void glBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, const GLvoid *);
449extern void glGetBufferSubDataARB (GLenum, GLintptrARB, GLsizeiptrARB, GLvoid *);
450extern GLvoid* glMapBufferARB (GLenum, GLenum);
451extern GLboolean glUnmapBufferARB (GLenum);
452extern void glGetBufferParameterivARB (GLenum, GLenum, GLint *);
453extern 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
46class LLGLDepthTest
47{
48 // Enabled by default
49public:
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;
92private:
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
100class LLGLSDefault
101{
102protected:
103 LLGLEnable mTexture2D, mColorMaterial;
104 LLGLDisable mAlphaTest, mBlend, mCullFace, mDither, mFog,
105 mLineSmooth, mLineStipple, mNormalize, mPolygonSmooth,
106 mTextureGenQ, mTextureGenR, mTextureGenS, mTextureGenT;
107public:
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
130class LLGLSTexture
131{
132protected:
133 LLGLEnable mTexture2D;
134public:
135 LLGLSTexture()
136 : mTexture2D(GL_TEXTURE_2D)
137 {}
138};
139
140
141class LLGLSNoTexture
142{
143protected:
144 LLGLDisable mTexture2D;
145public:
146 LLGLSNoTexture()
147 : mTexture2D(GL_TEXTURE_2D)
148 {}
149};
150
151class LLGLSObjectSelect // : public LLGLSDefault
152{
153protected:
154 LLGLDisable mBlend, mFog, mTexture2D, mAlphaTest;
155 LLGLEnable mCullFace;
156public:
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
164class LLGLSObjectSelectAlpha // : public LLGLSObjectSelect
165{
166protected:
167 LLGLEnable mTexture2D, mAlphaTest;
168public:
169 LLGLSObjectSelectAlpha()
170 : mTexture2D(GL_TEXTURE_2D), mAlphaTest(GL_ALPHA_TEST)
171 {}
172};
173
174//----------------------------------------------------------------------------
175
176class LLGLSUIDefault // : public LLGLSDefault
177{
178protected:
179 LLGLEnable mBlend, mAlphaTest, mTexture2D;
180 LLGLDisable mCullFace;
181 LLGLDepthTest mDepthTest;
182public:
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
191class LLGLSNoAlphaTest // : public LLGLSUIDefault
192{
193protected:
194 LLGLDisable mAlphaTest;
195public:
196 LLGLSNoAlphaTest()
197 : mAlphaTest(GL_ALPHA_TEST)
198 {}
199};
200
201class LLGLSNoTextureNoAlphaTest // : public LLGLSUIDefault
202{
203protected:
204 LLGLDisable mAlphaTest;
205 LLGLDisable mTexture2D;
206public:
207 LLGLSNoTextureNoAlphaTest()
208 : mAlphaTest(GL_ALPHA_TEST),
209 mTexture2D(GL_TEXTURE_2D)
210 {}
211};
212
213//----------------------------------------------------------------------------
214
215class LLGLSFog
216{
217protected:
218 LLGLEnable mFog;
219public:
220 LLGLSFog()
221 : mFog(GL_FOG)
222 {}
223};
224
225class LLGLSNoFog
226{
227protected:
228 LLGLDisable mFog;
229public:
230 LLGLSNoFog()
231 : mFog(GL_FOG)
232 {}
233};
234
235//----------------------------------------------------------------------------
236
237class LLGLSPipeline // : public LLGLSDefault
238{
239protected:
240 LLGLEnable mCullFace;
241 LLGLDepthTest mDepthTest;
242public:
243 LLGLSPipeline()
244 : mCullFace(GL_CULL_FACE),
245 mDepthTest(GL_TRUE, GL_TRUE, GL_LEQUAL)
246 { }
247};
248
249class LLGLSPipelineAlpha // : public LLGLSPipeline
250{
251protected:
252 LLGLEnable mBlend, mAlphaTest;
253public:
254 LLGLSPipelineAlpha()
255 : mBlend(GL_BLEND),
256 mAlphaTest(GL_ALPHA_TEST)
257 { }
258};
259
260class LLGLSPipelineEmbossBump // : public LLGLSPipelineAlpha
261{
262protected:
263 LLGLDisable mFog;
264public:
265 LLGLSPipelineEmbossBump()
266 : mFog(GL_FOG)
267 { }
268};
269
270class LLGLSPipelineSelection // : public LLGLSPipelineAlpha
271{
272protected:
273 LLGLDisable mCullFace;
274public:
275 LLGLSPipelineSelection()
276 : mCullFace(GL_CULL_FACE)
277 {}
278};
279
280class LLGLSPipelineAvatar // : public LLGLSPipeline
281{
282protected:
283 LLGLEnable mNormalize;
284public:
285 LLGLSPipelineAvatar()
286 : mNormalize(GL_NORMALIZE)
287 {}
288};
289
290class LLGLSPipelineSkyBox // : public LLGLSPipeline
291{
292protected:
293 LLGLDisable mAlphaTest, mCullFace, mFog;
294public:
295 LLGLSPipelineSkyBox()
296 : mAlphaTest(GL_ALPHA_TEST), mCullFace(GL_CULL_FACE), mFog(GL_FOG)
297 { }
298};
299
300class LLGLSTracker // : public LLGLSDefault
301{
302protected:
303 LLGLEnable mCullFace, mBlend, mAlphaTest;
304 LLGLDisable mTexture2D;
305public:
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
316class LLGLSSpecular
317{
318public:
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
35GL_FUNC(void,glAlphaFunc,(GLenum f,GLclampf x),(f,x),)
36GL_FUNC(void,glBegin,(GLenum e),(e),)
37GL_FUNC(void,glBindTexture,(GLenum target,GLuint name),(target,name),)
38GL_FUNC(void,glBlendFunc,(GLenum f,GLenum x),(f,x),)
39GL_FUNC(void,glCallLists,(GLsizei a,GLenum b,const GLvoid* c),(a,b,c),)
40GL_FUNC(void,glClear,(GLbitfield a),(a),)
41GL_FUNC(void,glClearColor,(GLclampf r,GLclampf g,GLclampf b,GLclampf a),(r,g,b,a),)
42GL_FUNC(void,glClearDepth,(GLclampd x),(x),)
43GL_FUNC(void,glColor3f,(GLfloat r,GLfloat g,GLfloat b),(r,g,b),)
44GL_FUNC(void,glColor4f,(GLfloat r,GLfloat g,GLfloat b,GLfloat a),(r,g,b,a),)
45GL_FUNC(void,glColorMask,(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha),(red,green,blue,alpha),)
46GL_FUNC(void,glColorPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size, type, stride, pointer),)
47GL_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),)
48GL_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),)
49GL_FUNC(void,glCullFace,(GLenum mode),(mode),)
50GL_FUNC(void,glDeleteLists,(GLuint list, GLsizei range),(list,range),)
51GL_FUNC(void,glDeleteTextures,(GLsizei n, const GLuint *textures),(n,textures),)
52GL_FUNC(void,glDepthFunc,(GLenum func),(func),)
53GL_FUNC(void,glDepthMask,(GLboolean flag),(flag),)
54GL_FUNC(void,glDisable,(GLenum cap),(cap),)
55GL_FUNC(void,glDisableClientState,(GLenum array),(array),)
56GL_FUNC(void,glDrawArrays,(GLenum mode, GLint first, GLsizei count),(mode,first,count),)
57GL_FUNC(void,glDrawBuffer,(GLenum mode),(mode),)
58GL_FUNC(void,glEnable,(GLenum cap),(cap),)
59GL_FUNC(void,glEnableClientState,(GLenum array),(array),)
60GL_FUNC(void,glEnd,(void),(),)
61GL_FUNC(void,glEndList,(void),(),)
62GL_FUNC(GLuint,glGenLists,(GLsizei range),(range),return)
63GL_FUNC(void,glGenTextures,(GLsizei n, GLuint *textures),(n,textures),)
64GL_FUNC(GLenum,glGetError,(void),(),return)
65GL_FUNC(void,glGetFloatv,(GLenum pname, GLfloat *params),(pname,params),)
66GL_FUNC(void,glHint,(GLenum target, GLenum mode),(target,mode),)
67GL_FUNC(void,glInterleavedArrays,(GLenum format, GLsizei stride, const GLvoid *pointer),(format,stride,pointer),)
68GL_FUNC(GLboolean,glIsTexture,(GLuint texture),(texture),return)
69GL_FUNC(void,glLightfv,(GLenum light, GLenum pname, const GLfloat *params),(light,pname,params),)
70GL_FUNC(void,glListBase,(GLuint base),(base),)
71GL_FUNC(void,glLoadIdentity,(void),(),)
72GL_FUNC(void,glLoadMatrixf,(const GLfloat *m),(m),)
73GL_FUNC(void,glMatrixMode,(GLenum mode),(mode),)
74GL_FUNC(void,glNewList,(GLuint list, GLenum mode),(list,mode),)
75GL_FUNC(void,glNormal3f,(GLfloat nx, GLfloat ny, GLfloat nz),(nx,ny,nz),)
76GL_FUNC(void,glOrtho,(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar),(left,right,bottom,top,zNear,zFar),)
77GL_FUNC(void,glPixelStorei,(GLenum pname, GLint param),(pname,param),)
78GL_FUNC(void,glPixelTransferi,(GLenum pname, GLint param),(pname,param),)
79GL_FUNC(void,glPointSize,(GLfloat size),(size),)
80GL_FUNC(void,glPopMatrix,(void),(),)
81GL_FUNC(void,glPushMatrix,(void),(),)
82GL_FUNC(void,glReadBuffer,(GLenum mode),(mode),)
83GL_FUNC(void,glReadPixels,(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels),(x,y,width,height,format,type,pixels),)
84GL_FUNC(void,glRotatef,(GLfloat angle, GLfloat x, GLfloat y, GLfloat z),(angle,x,y,z),)
85GL_FUNC(void,glScalef,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),)
86GL_FUNC(void,glShadeModel,(GLenum mode),(mode),)
87GL_FUNC(void,glTexCoord2f,(GLfloat s, GLfloat t),(s,t),)
88GL_FUNC(void,glTexCoordPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size,type,stride,pointer),)
89GL_FUNC(void,glTexEnvf,(GLenum target, GLenum pname, GLfloat param),(target,pname,param),)
90GL_FUNC(void,glTexEnvfv,(GLenum target, GLenum pname, const GLfloat *params),(target,pname,params),)
91GL_FUNC(void,glTexEnvi,(GLenum target, GLenum pname, GLint param),(target,pname,param),)
92GL_FUNC(void,glTexParameterf,(GLenum target, GLenum pname, GLfloat param),(target,pname,param),)
93GL_FUNC(void,glTexParameteri,(GLenum target, GLenum pname, GLint param),(target,pname,param),)
94GL_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),)
95GL_FUNC(void,glTranslated,(GLdouble x, GLdouble y, GLdouble z),(x,y,z),)
96GL_FUNC(void,glTranslatef,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),)
97GL_FUNC(void,glVertex2i,(GLint x, GLint y),(x,y),)
98GL_FUNC(void,glVertex2f,(GLfloat x, GLfloat y),(x,y),)
99GL_FUNC(void,glVertex3f,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),)
100GL_FUNC(void,glVertexPointer,(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer),(size,type,stride,pointer),)
101GL_FUNC(void,glViewport,(GLint x, GLint y, GLsizei width, GLsizei height),(x,y,width,height),)
102GL_FUNC(void,glLockArraysEXT,(GLint first, GLsizei count),(first,count),)
103GL_FUNC(void,glUnlockArraysEXT,(void),(),)
104GL_FUNC(void,glGetIntegerv,(GLenum pname, GLint *params),(pname,params),)
105GL_FUNC(const GLubyte *,glGetString,(GLenum name),(name),return)
106GL_FUNC(void,glGetTexLevelParameteriv,(GLenum target, GLint level, GLenum pname, GLint *params),(target,level,pname,params),)
107GL_FUNC(void,glMultMatrixd,(const GLdouble *m),(m),)
108GL_FUNC(void,glMultMatrixf,(const GLfloat *m),(m),)
109GL_FUNC(void,glGetTexImage,(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels),(target,level,format,type,pixels),)
110GL_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),)
111GL_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),)
112GL_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),)
113GL_FUNC(void,glDepthRange,(GLclampd near_val, GLclampd far_val),(near_val,far_val),)
114GL_FUNC(void,glCallList,(GLuint list),(list),)
115GL_FUNC(void,glClearStencil,(GLint s),(s),)
116GL_FUNC(void,glColor3d,(GLdouble red, GLdouble green, GLdouble blue),(red,green,blue),)
117GL_FUNC(void,glColor3dv,(const GLdouble *v),(v),)
118GL_FUNC(void,glColor3fv,(const GLfloat *v),(v),)
119GL_FUNC(void,glColor4dv,(const GLdouble *v),(v),)
120GL_FUNC(void,glColor4fv,(const GLfloat *v),(v),)
121GL_FUNC(void,glColor4ub,(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha),(red,green,blue,alpha),)
122GL_FUNC(void,glColor4ubv,(const GLubyte *v),(v),)
123GL_FUNC(void,glColorMaterial,(GLenum face, GLenum mode),(face,mode),)
124GL_FUNC(void,glClientActiveTextureARB,(GLenum x),(x),)
125GL_FUNC(void,glActiveTextureARB,(GLenum texture),(texture),)
126GL_FUNC(GLboolean,glAreTexturesResident,(GLsizei n, const GLuint *textures, GLboolean *residences),(n,textures,residences),return)
127GL_FUNC(void,glClipPlane,(GLenum plane, const GLdouble *equation),(plane,equation),)
128GL_FUNC(void,glBindBufferARB,(GLenum x, GLuint y),(x,y),)
129GL_FUNC(void,glDeleteBuffersARB,(GLsizei x, const GLuint *y),(x,y),)
130GL_FUNC(void,glGenBuffersARB,(GLsizei x, GLuint *y),(x,y),)
131GL_FUNC(void,glBufferDataARB,(GLenum a, GLsizeiptrARB b, const GLvoid *c, GLenum d),(a,b,c,d),)
132GL_FUNC(void,glBufferSubDataARB,(GLenum a, GLintptr b, GLsizeiptr c, const GLvoid *d),(a,b,c,d),)
133GL_FUNC(void,glProgramStringARB,(GLenum a, GLenum b, GLsizei c, const GLvoid *d),(a,b,c,d),)
134GL_FUNC(void,glBindProgramARB,(GLenum a, GLuint b),(a,b),)
135GL_FUNC(void,glDeleteProgramsARB,(GLsizei a, const GLuint *b),(a,b),)
136GL_FUNC(void,glGenProgramsARB,(GLsizei a, GLuint *b),(a,b),)
137GL_FUNC(void,glProgramEnvParameter4dARB,(GLenum a, GLuint b, GLdouble c, GLdouble d, GLdouble e, GLdouble f),(a,b,c,d,e,f),)
138GL_FUNC(void,glProgramEnvParameter4dvARB,(GLenum a, GLuint b, const GLdouble *c),(a,b,c),)
139GL_FUNC(void,glProgramEnvParameter4fARB,(GLenum a, GLuint b, GLfloat c, GLfloat d, GLfloat e, GLfloat f),(a,b,c,d,e,f),)
140GL_FUNC(void,glProgramEnvParameter4fvARB,(GLenum a, GLuint b, const GLfloat *c),(a,b,c),)
141GL_FUNC(void,glProgramLocalParameter4dARB,(GLenum a, GLuint b, GLdouble c, GLdouble d, GLdouble e, GLdouble f),(a,b,c,d,e,f),)
142GL_FUNC(void,glProgramLocalParameter4dvARB,(GLenum a, GLuint b, const GLdouble *c),(a,b,c),)
143GL_FUNC(void,glProgramLocalParameter4fARB,(GLenum a, GLuint b, GLfloat c, GLfloat d, GLfloat e, GLfloat f),(a,b,c,d,e,f),)
144GL_FUNC(void,glProgramLocalParameter4fvARB,(GLenum a, GLuint b, const GLfloat *c),(a,b,c),)
145GL_FUNC(void,glGetProgramEnvParameterdvARB,(GLenum a, GLuint b, GLdouble *c),(a,b,c),)
146GL_FUNC(void,glGetProgramEnvParameterfvARB,(GLenum a, GLuint b, GLfloat *c),(a,b,c),)
147GL_FUNC(void,glGetProgramLocalParameterdvARB,(GLenum a, GLuint b, GLdouble *c),(a,b,c),)
148GL_FUNC(void,glGetProgramLocalParameterfvARB,(GLenum a, GLuint b, GLfloat *c),(a,b,c),)
149GL_FUNC(void,glGetProgramivARB,(GLenum a, GLenum b, GLint *c),(a,b,c),)
150GL_FUNC(void,glGetProgramStringARB,(GLenum a, GLenum b, GLvoid *c),(a,b,c),)
151GL_FUNC(GLboolean,glIsProgramARB,(GLuint a),(a),return)
152GL_FUNC(void,glColorTableEXT,(GLenum a, GLenum b, GLsizei c, GLenum d, GLenum e, const GLvoid *f),(a,b,c,d,e,f),)
153GL_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),)
154GL_FUNC(void,glEnableVertexAttribArrayARB,(GLuint a),(a),)
155GL_FUNC(void,glDisableVertexAttribArrayARB,(GLuint a),(a),)
156GL_FUNC(void,glDrawElements,(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices),(mode,count,type,indices),)
157GL_FUNC(void,glDrawPixels,(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels),(width,height,format,type,pixels),)
158GL_FUNC(void,glDrawRangeElements,(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices),(mode,start,end,count,type,indices),)
159GL_FUNC(void,glFlush,(void),(),)
160GL_FUNC(void,glFogf,(GLenum pname, GLfloat param),(pname,param),)
161GL_FUNC(void,glFogfv,(GLenum pname, const GLfloat *params),(pname,params),)
162GL_FUNC(void,glFogi,(GLenum pname, GLint param),(pname,param),)
163GL_FUNC(void,glFrontFace,(GLenum mode),(mode),)
164GL_FUNC(void,glGetBooleanv,(GLenum pname, GLboolean *params),(pname,params),)
165GL_FUNC(void,glGetDoublev,(GLenum pname, GLdouble *params),(pname,params),)
166GL_FUNC(void,glGetMaterialfv,(GLenum face, GLenum pname, GLfloat *params),(face,pname,params),)
167GL_FUNC(void,glGetLightfv,(GLenum light, GLenum pname, GLfloat *params),(light,pname,params),)
168GL_FUNC(GLboolean,glIsEnabled,(GLenum cap),(cap),return)
169GL_FUNC(void,glGetCompressedTexImageARB,(GLenum a, GLint b, GLvoid *c),(a,b,c),)
170GL_FUNC(void,glLightf,(GLenum light, GLenum pname, GLfloat param),(light,pname,param),)
171GL_FUNC(void,glLightModelfv,(GLenum pname, const GLfloat *params),(pname,params),)
172GL_FUNC(void,glLightModeli,(GLenum pname, GLint param),(pname,param),)
173GL_FUNC(void,glLightModeliv,(GLenum pname, const GLint *params),(pname,params),)
174GL_FUNC(void,glLineStipple,(GLint factor, GLushort pattern),(factor,pattern),)
175GL_FUNC(void,glLineWidth,(GLfloat width),(width),)
176GL_FUNC(void,glPushAttrib,(GLbitfield mask),(mask),)
177GL_FUNC(void,glPopAttrib,(void),(),)
178GL_FUNC(void,glLogicOp,(GLenum opcode),(opcode),)
179GL_FUNC(void,glMaterialf,(GLenum face, GLenum pname, GLfloat param),(face,pname,param),)
180GL_FUNC(void,glMateriali,(GLenum face, GLenum pname, GLint param),(face,pname,param),)
181GL_FUNC(void,glMaterialfv,(GLenum face, GLenum pname, const GLfloat *params),(face,pname,params),)
182GL_FUNC(void,glNormal3d,(GLdouble nx, GLdouble ny, GLdouble nz),(nx,ny,nz),)
183GL_FUNC(void,glNormal3dv,(const GLdouble *v),(v),)
184GL_FUNC(void,glNormal3fv,(const GLfloat *v),(v),)
185GL_FUNC(void,glNormalPointer,(GLenum type, GLsizei stride, const GLvoid *ptr),(type,stride,ptr),)
186GL_FUNC(void,glPolygonMode,(GLenum face, GLenum mode),(face,mode),)
187GL_FUNC(void,glPolygonOffset,(GLfloat factor, GLfloat units),(factor,units),)
188GL_FUNC(void,glPolygonStipple,(const GLubyte *mask),(mask),)
189GL_FUNC(void,glRotated,(GLdouble angle, GLdouble x, GLdouble y, GLdouble z),(angle,x,y,z),)
190GL_FUNC(void,glStencilFunc,(GLenum func, GLint ref, GLuint mask),(func,ref,mask),)
191GL_FUNC(void,glStencilMask,(GLuint mask),(mask),)
192GL_FUNC(void,glScissor,(GLint x, GLint y, GLsizei width, GLsizei height),(x,y,width,height),)
193GL_FUNC(void,glStencilOp,(GLenum fail, GLenum zfail, GLenum zpass),(fail,zfail,zpass),)
194GL_FUNC(void,glTexCoord2i,(GLint s, GLint t),(s,t),)
195GL_FUNC(void,glTexCoord2fv,(const GLfloat *v),(v),)
196GL_FUNC(void,glTexGenfv,(GLenum coord, GLenum pname, const GLfloat *params),(coord,pname,params),)
197GL_FUNC(void,glTexGeni,(GLenum coord, GLenum pname, GLint param),(coord,pname,param),)
198GL_FUNC(void,glTexParameterfv,(GLenum target, GLenum pname, const GLfloat *params),(target,pname,params),)
199GL_FUNC(void,glVertex2d,(GLdouble x, GLdouble y),(x,y),)
200GL_FUNC(void,glVertex2dv,(const GLdouble *v),(v),)
201GL_FUNC(void,glVertex2fv,(const GLfloat *v),(v),)
202GL_FUNC(void,glVertex3dv,(const GLdouble *v),(v),)
203GL_FUNC(void,glVertex3fv,(const GLfloat *v),(v),)
204GL_FUNC(void,glVertex4dv,(const GLdouble *v),(v),)
205GL_FUNC(void,glEvalPoint1,(GLint i),(i),)
206GL_FUNC(void,glEvalPoint2,(GLint i, GLint j),(i,j),)
207GL_FUNC(void,glEvalCoord1f,(GLfloat u),(u),)
208GL_FUNC(void,glEvalCoord2f,(GLfloat u, GLfloat v),(u,v),)
209GL_FUNC(void,glEvalMesh1,(GLenum mode, GLint i1, GLint i2),(mode,i1,i2),)
210GL_FUNC(void,glEvalMesh2,(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2),(mode,i1,i2,j1,j2),)
211GL_FUNC(void,glMapGrid1f,(GLint un, GLfloat u1, GLfloat u2),(un,u1,u2),)
212GL_FUNC(void,glMapGrid2d,(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2),(un,u1,u2,vn,v1,v2),)
213GL_FUNC(void,glMapGrid2f,(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2),(un,u1,u2,vn,v1,v2),)
214GL_FUNC(void,glMap1f,(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points),(target,u1,u2,stride,order,points),)
215GL_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),)
216GL_FUNC(void,glVertexAttribPointerARB,(GLuint a, GLint b, GLenum c, GLboolean d, GLsizei e, const GLvoid *f),(a,b,c,d,e,f),)
217GL_FUNC(GLuint,glNewObjectBufferATI,(GLsizei a, const GLvoid *b, GLenum c),(a,b,c),return)
218GL_FUNC(void,glUpdateObjectBufferATI,(GLuint a, GLuint b, GLsizei c, const GLvoid *d, GLenum e),(a,b,c,d,e),)
219GL_FUNC(void,glFreeObjectBufferATI,(GLuint a),(a),)
220GL_FUNC(void,glArrayObjectATI,(GLenum a, GLint b, GLenum c, GLsizei d, GLuint e, GLuint f),(a,b,c,d,e,f),)
221GL_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
225GL_FUNC(void*,glXGetCurrentDisplay,(void),(),return)
226GL_FUNC(const char *,glXQueryExtensionsString,(void *dpy, int screen),(dpy,screen),return)
227GL_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
33typedef U32 LLGLenum;
34typedef U32 LLGLuint;
35typedef S32 LLGLint;
36typedef F32 LLGLfloat;
37typedef F64 LLGLdouble;
38typedef 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
39LLKeyboard *gKeyboard = NULL;
40
41//static
42std::map<KEY,LLString> LLKeyboard::sKeysToNames;
43std::map<LLString,KEY> LLKeyboard::sNamesToKeys;
44
45//
46// Class Implementation
47//
48
49LLKeyboard::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
136LLKeyboard::~LLKeyboard()
137{
138 // nothing
139}
140
141void 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
151void 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
181BOOL 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
201U16 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
216BOOL 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
244BOOL 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
266void 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.
280F32 LLKeyboard::getKeyElapsedTime(KEY key)
281{
282 return mKeyLevelTimer[key].getElapsedTimeF32();
283}
284
285// Returns time in frames since key was pressed.
286S32 LLKeyboard::getKeyElapsedFrameCount(KEY key)
287{
288 return mKeyLevelFrameCount[key];
289}
290
291// static
292BOOL 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
329LLString 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
345BOOL 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
37enum EKeystate
38{
39 KEYSTATE_DOWN,
40 KEYSTATE_LEVEL,
41 KEYSTATE_UP
42};
43
44typedef void (*LLKeyFunc)(EKeystate keystate);
45
46enum EKeyboardInsertMode
47{
48 LL_KIM_INSERT,
49 LL_KIM_OVERWRITE
50};
51
52class LLKeyBinding
53{
54public:
55 KEY mKey;
56 MASK mMask;
57// const char *mName; // unused
58 LLKeyFunc mFunction;
59};
60
61class LLWindowCallbacks;
62
63class LLKeyboard
64{
65public:
66 typedef enum e_numpad_distinct
67 {
68 ND_NEVER,
69 ND_NUMLOCK_OFF,
70 ND_NUMLOCK_ON
71 } ENumpadDistinct;
72
73public:
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
117protected:
118 void addKeyName(KEY key, const LLString& name);
119
120protected:
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
142extern 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
36LLKeyboardMacOSX::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
164void 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/*
189static 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
200MASK 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
223BOOL 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
240BOOL 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
256MASK 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
274void 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
301BOOL 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
315U16 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
33class LLKeyboardMacOSX : public LLKeyboard
34{
35public:
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
45protected:
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);
50private:
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
35LLKeyboardSDL::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
156void 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
181MASK 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
205static 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
230BOOL 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
250BOOL 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
269MASK 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
287void 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
314BOOL 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
329U16 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
34class LLKeyboardSDL : public LLKeyboard
35{
36public:
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
46protected:
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);
51private:
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
40LLKeyboardWin32::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.
147void 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
183MASK 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
201BOOL 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
219BOOL 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
236MASK 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
248void 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
296BOOL 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
357U16 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 '/')
35const MASK MASK_EXTENDED = 0x0100;
36
37class LLKeyboardWin32 : public LLKeyboard
38{
39public:
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
51protected:
52 MASK updateModifiers();
53 //void setModifierKeyLevel( KEY key, BOOL new_state );
54private:
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
35class LLMouseHandler
36{
37public:
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
48LLWindowCallbacks LLWindow::sDefaultCallbacks;
49
50//
51// LLWindowCallbacks
52//
53
54LLSplashScreen *gSplashScreenp = NULL;
55BOOL gDebugClicks = FALSE;
56BOOL gDebugWindowProc = FALSE;
57
58const S32 gURLProtocolWhitelistCount = 3;
59const 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
65const char* gURLProtocolWhitelistHandler[] = { "http", "http", "https" };
66
67BOOL LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, BOOL repeated)
68{
69 return FALSE;
70}
71
72
73BOOL LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask)
74{
75 return FALSE;
76}
77
78void LLWindowCallbacks::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
79{
80}
81
82BOOL LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask)
83{
84 return FALSE;
85}
86
87
88BOOL LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask)
89{
90 return FALSE;
91}
92
93BOOL LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask)
94{
95 return FALSE;
96}
97
98void LLWindowCallbacks::handleMouseLeave(LLWindow *window)
99{
100 return;
101}
102
103BOOL LLWindowCallbacks::handleCloseRequest(LLWindow *window)
104{
105 //allow the window to close
106 return TRUE;
107}
108
109void LLWindowCallbacks::handleQuit(LLWindow *window)
110{
111 if(LLWindowManager::destroyWindow(window) == FALSE)
112 {
113 llerrs << "LLWindowCallbacks::handleQuit() : Couldn't destroy window" << llendl;
114 }
115}
116
117BOOL LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask)
118{
119 return FALSE;
120}
121
122BOOL LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask)
123{
124 return FALSE;
125}
126
127BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated)
128{
129 return FALSE;
130}
131
132void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask)
133{
134}
135
136void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks)
137{
138}
139
140void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height)
141{
142}
143
144void LLWindowCallbacks::handleFocus(LLWindow *window)
145{
146}
147
148void LLWindowCallbacks::handleFocusLost(LLWindow *window)
149{
150}
151
152void LLWindowCallbacks::handleMenuSelect(LLWindow *window, const S32 menu_item)
153{
154}
155
156BOOL LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y,
157 const S32 width, const S32 height)
158{
159 return FALSE;
160}
161
162BOOL LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask)
163{
164 return FALSE;
165}
166
167void LLWindowCallbacks::handleWindowBlock(LLWindow *window)
168{
169}
170
171void LLWindowCallbacks::handleWindowUnblock(LLWindow *window)
172{
173}
174
175void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *data)
176{
177}
178
179
180S32 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
217LLWindow::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
238void LLWindow::incBusyCount()
239{
240 ++mBusyCount;
241}
242
243// virtual
244void LLWindow::decBusyCount()
245{
246 if (mBusyCount > 0)
247 {
248 --mBusyCount;
249 }
250}
251
252void 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
266bool LLSplashScreen::isVisible()
267{
268 return gSplashScreenp ? true: false;
269}
270
271// static
272LLSplashScreen *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
287void 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
304void LLSplashScreen::update(const char* str)
305{
306 LLSplashScreen::show();
307 if (gSplashScreenp)
308 {
309 gSplashScreenp->updateImpl(str);
310 }
311}
312
313//static
314void 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
329static LLLinkedList<LLWindow> sWindowList;
330
331LLWindow* 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
348LLWindow* 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
399BOOL 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
417BOOL 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
38enum 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
76class LLSplashScreen;
77
78class LLWindow;
79
80class LLWindowCallbacks
81{
82public:
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
114class LLWindow
115{
116public:
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 };
132public:
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
215protected:
216 LLWindow(BOOL fullscreen, U32 flags);
217 virtual ~LLWindow() {}
218 virtual BOOL isValid() {return TRUE;}
219 virtual BOOL canDelete() {return TRUE;}
220protected:
221 static LLWindowCallbacks sDefaultCallbacks;
222
223protected:
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
252class LLSplashScreen
253{
254public:
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();
266protected:
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
277S32 OSMessageBox(const char* text, const char* caption, U32 type);
278const U32 OSMB_OK = 0;
279const U32 OSMB_OKCANCEL = 1;
280const U32 OSMB_YESNO = 2;
281
282const S32 OSBTN_YES = 0;
283const S32 OSBTN_NO = 1;
284const S32 OSBTN_OK = 2;
285const S32 OSBTN_CANCEL = 3;
286
287//
288// LLWindowManager
289// Manages window creation and error checking
290
291class LLWindowManager
292{
293public:
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
322extern const S32 gURLProtocolWhitelistCount;
323extern const char* gURLProtocolWhitelist[];
324extern const char* gURLProtocolWhitelistHandler[];
325
326// Loads a URL with the user's default browser
327void spawn_web_browser(const char* escaped_url);
328
329// Opens a file with ShellExecute. Security risk!
330void shell_open(const char* file_path);
331
332void 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//
36LLWindowHeadless::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
44LLWindowHeadless::~LLWindowHeadless()
45{
46}
47
48void 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
33class LLWindowHeadless : public LLWindow
34{
35public:
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
101private:
102};
103
104class LLSplashScreenHeadless : public LLSplashScreen
105{
106public:
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//
40LLWindowLinux::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
49LLWindowLinux::~LLWindowLinux()
50{
51}
52
53void 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
33class LLWindowLinux : public LLWindow
34{
35public:
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
103class LLSplashScreenLinux : public LLSplashScreen
104{
105public:
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.
31typedef void *CursorRef;
32
33/* Defined in llwindowmacosx-objc.mm: */
34void setupCocoa();
35CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY);
36OSErr releaseImageCursor(CursorRef ref);
37OSErr 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
40void 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
57CursorRef 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.
77OSErr 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
92OSErr 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
47extern 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.
53const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */
54const S32 BITS_PER_PIXEL = 32;
55const S32 MAX_NUM_RESOLUTIONS = 32;
56
57
58//
59// LLWindowMacOSX
60//
61
62// Cross-platform bits:
63
64void 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
88BOOL 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
127static double getDictDouble (CFDictionaryRef refDict, CFStringRef key);
128static long getDictLong (CFDictionaryRef refDict, CFStringRef key);
129
130
131
132
133// CarbonEvents we're interested in.
134static 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
174static 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
196static 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.
206static LLWindowMacOSX *gWindowImplementation = NULL;
207
208
209
210LLWindowMacOSX::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
305BOOL 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.
747BOOL 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
844void 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
927LLWindowMacOSX::~LLWindowMacOSX()
928{
929 destroyContext();
930
931 if(mSupportedResolutions != NULL)
932 {
933 delete []mSupportedResolutions;
934 }
935
936 gWindowImplementation = NULL;
937
938}
939
940
941void LLWindowMacOSX::show()
942{
943 if(IsWindowCollapsed(mWindow))
944 CollapseWindow(mWindow, false);
945
946 MacShowWindow(mWindow);
947 BringToFront(mWindow);
948}
949
950void LLWindowMacOSX::hide()
951{
952 setMouseClipping(FALSE);
953 HideWindow(mWindow);
954}
955
956void LLWindowMacOSX::minimize()
957{
958 setMouseClipping(FALSE);
959 showCursor();
960 CollapseWindow(mWindow, true);
961}
962
963void 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()
971void 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
986BOOL LLWindowMacOSX::isValid()
987{
988 if(mFullscreen)
989 {
990 return(TRUE);
991 }
992
993 return (mWindow != NULL);
994}
995
996BOOL 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
1012BOOL 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
1023BOOL LLWindowMacOSX::getMaximized()
1024{
1025 BOOL result = FALSE;
1026
1027 if (mWindow)
1028 {
1029 // TODO
1030 }
1031
1032 return(result);
1033}
1034
1035BOOL LLWindowMacOSX::maximize()
1036{
1037 // TODO
1038 return FALSE;
1039}
1040
1041BOOL LLWindowMacOSX::getFullscreen()
1042{
1043 return mFullscreen;
1044}
1045
1046void 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
1094BOOL 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
1120BOOL 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
1146BOOL 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
1172BOOL 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
1182BOOL 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
1192void LLWindowMacOSX::swapBuffers()
1193{
1194 aglSwapBuffers(mContext);
1195}
1196
1197F32 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
1231BOOL LLWindowMacOSX::restoreGamma()
1232{
1233 CGDisplayRestoreColorSyncSettings();
1234 return true;
1235}
1236
1237BOOL 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
1285BOOL LLWindowMacOSX::isCursorHidden()
1286{
1287 return mCursorHidden;
1288}
1289
1290
1291
1292// Constrains the mouse to the window.
1293void 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
1310BOOL 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
1339static 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
1353BOOL 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
1394void 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
1422F32 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
1442F32 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
1452void 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
1479void 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
1501S32 LLWindowMacOSX::stat(const char* file_name, struct stat* stat_info)
1502{
1503 return ::stat( file_name, stat_info );
1504}
1505
1506void 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
1530BOOL 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
1550BOOL 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
1607BOOL 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
1635BOOL 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
1645BOOL 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
1652LLWindow::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
1702BOOL 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
1729BOOL 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
1756BOOL 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
1790BOOL 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
1823BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to)
1824{
1825 LLCoordWindow window_coord;
1826
1827 return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));
1828}
1829
1830BOOL 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
1840void LLWindowMacOSX::setupFailure(const char* text, const char* caption, U32 type)
1841{
1842 destroyContext();
1843
1844 OSMessageBox(text, caption, type);
1845}
1846
1847pascal OSStatus LLWindowMacOSX::staticEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData)
1848{
1849 LLWindowMacOSX *self = (LLWindowMacOSX*)userData;
1850
1851 return(self->eventHandler(myHandler, event));
1852}
1853
1854OSStatus 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, &currentBounds);
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), &currentBounds);
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
2293const 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
2338static CursorRef gCursors[UI_CURSOR_COUNT];
2339
2340
2341static 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
2354void 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
2439ECursorType LLWindowMacOSX::getCursor()
2440{
2441 return mCurrentCursor;
2442}
2443
2444void 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
2476void 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
2482void 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
2488void 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
2505void 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
2522void LLWindowMacOSX::showCursorFromMouseMove()
2523{
2524 if (!mHideCursorPermanent)
2525 {
2526 showCursor();
2527 }
2528}
2529
2530void LLWindowMacOSX::hideCursorUntilMouseMove()
2531{
2532 if (!mHideCursorPermanent)
2533 {
2534 hideCursor();
2535 mHideCursorPermanent = FALSE;
2536 }
2537}
2538
2539
2540
2541//
2542// LLSplashScreenMacOSX
2543//
2544LLSplashScreenMacOSX::LLSplashScreenMacOSX()
2545{
2546 mWindow = NULL;
2547}
2548
2549LLSplashScreenMacOSX::~LLSplashScreenMacOSX()
2550{
2551}
2552
2553void 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
2576void 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
2613void LLSplashScreenMacOSX::hideImpl()
2614{
2615 if(mWindow != NULL)
2616 {
2617 DisposeWindow(mWindow);
2618 mWindow = NULL;
2619 }
2620}
2621
2622
2623
2624S32 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 &params,
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.
2735void 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
2790void 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
2831BOOL 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
2864static WindowRef dummywindowref = NULL;
2865
2866void *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
2893void LLWindowMacOSX::stopDockTileBounce()
2894{
2895 NMRemove(&mBounceRec);
2896 mBounceTimer.stop();
2897}
2898
2899// get a double value from a dictionary
2900static 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
2912static 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
42class LLWindowMacOSX : public LLWindow
43{
44public:
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
110protected:
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
137protected:
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
189class LLSplashScreenMacOSX : public LLSplashScreen
190{
191public:
192 LLSplashScreenMacOSX();
193 virtual ~LLSplashScreenMacOSX();
194
195 /*virtual*/ void showImpl();
196 /*virtual*/ void updateImpl(const char* mesg);
197 /*virtual*/ void hideImpl();
198
199private:
200 WindowRef mWindow;
201};
202
203S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type);
204
205void load_url_external(const char* url);
206void 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
40U16 *gMesaBuffer = NULL;
41
42//
43// LLWindowMesaHeadless
44//
45LLWindowMesaHeadless::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
72LLWindowMesaHeadless::~LLWindowMesaHeadless()
73{
74 delete mMesaBuffer;
75 OSMesaDestroyContext( mMesaContext );
76}
77
78void 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
36class LLWindowMesaHeadless : public LLWindow
37{
38public:
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
104private:
105 OSMesaContext mMesaContext;
106 unsigned char * mMesaBuffer;
107};
108
109class LLSplashScreenMesaHeadless : public LLSplashScreen
110{
111public:
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
55extern 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.
61const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */
62const S32 BITS_PER_PIXEL = 32;
63const 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.
76static Display *SDL_Display = NULL;
77static 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.
85static LLWindowSDL *gWindowImplementation = NULL;
86
87static BOOL was_fullscreen = FALSE;
88
89// Cross-platform bits:
90
91void 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.
118static 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
152BOOL 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
188LLWindowSDL::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
242static 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
258BOOL 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.
563BOOL 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
589void 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
606LLWindowSDL::~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
622void LLWindowSDL::show()
623{
624 // *FIX: What to do with SDL?
625}
626
627void LLWindowSDL::hide()
628{
629 // *FIX: What to do with SDL?
630}
631
632void LLWindowSDL::minimize()
633{
634 // *FIX: What to do with SDL?
635}
636
637void 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()
645void 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
660BOOL LLWindowSDL::isValid()
661{
662 return (mWindow != NULL);
663}
664
665BOOL 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
679BOOL LLWindowSDL::getMinimized()
680{
681 BOOL result = FALSE;
682
683 if (mWindow && (1 == mIsMinimized))
684 {
685 result = TRUE;
686 }
687 return(result);
688}
689
690BOOL LLWindowSDL::getMaximized()
691{
692 BOOL result = FALSE;
693
694 if (mWindow)
695 {
696 // TODO
697 }
698
699 return(result);
700}
701
702BOOL LLWindowSDL::maximize()
703{
704 // TODO
705 return FALSE;
706}
707
708BOOL LLWindowSDL::getFullscreen()
709{
710 return mFullscreen;
711}
712
713BOOL 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
721BOOL 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
734BOOL 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
747BOOL 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
758BOOL 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
769void LLWindowSDL::swapBuffers()
770{
771 if (mWindow)
772 SDL_GL_SwapBuffers();
773}
774
775F32 LLWindowSDL::getGamma()
776{
777 return 1/mGamma;
778}
779
780BOOL LLWindowSDL::restoreGamma()
781{
782 //CGDisplayRestoreColorSyncSettings();
783 SDL_SetGamma(1.0f, 1.0f, 1.0f);
784 return true;
785}
786
787BOOL 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
796BOOL LLWindowSDL::isCursorHidden()
797{
798 return mCursorHidden;
799}
800
801
802
803// Constrains the mouse to the window.
804void 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
813BOOL 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
833BOOL 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
848void 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
876F32 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
915F32 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.
932static LLCoordScreen old_size;
933static BOOL old_fullscreen;
934void 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
966void 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
979S32 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
986void 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
1010void 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
1065typedef Atom x11clipboard_type;
1066
1067static
1068x11clipboard_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. */
1092static int
1093convert_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. */
1124static int
1125convert_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
1153int
1154LLWindowSDL::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
1165void
1166LLWindowSDL::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
1212void
1213LLWindowSDL::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
1299int 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
1379int
1380LLWindowSDL::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
1415void
1416LLWindowSDL::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
1429BOOL LLWindowSDL::isClipboardTextAvailable()
1430{
1431 return !is_empty_x11clipboard();
1432}
1433
1434BOOL 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
1469BOOL 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
1492BOOL LLWindowSDL::isClipboardTextAvailable()
1493{
1494 return FALSE; // unsupported
1495}
1496
1497BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)
1498{
1499 return FALSE; // unsupported
1500}
1501
1502BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)
1503{
1504 return FALSE; // unsupported
1505}
1506#endif // LL_X11
1507
1508BOOL 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
1517LLWindow::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
1560BOOL 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
1571BOOL 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
1582BOOL 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
1593BOOL 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
1604BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to)
1605{
1606 LLCoordWindow window_coord;
1607
1608 return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));
1609}
1610
1611BOOL 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
1621void LLWindowSDL::setupFailure(const char* text, const char* caption, U32 type)
1622{
1623 destroyContext();
1624
1625 OSMessageBox(text, caption, type);
1626}
1627
1628BOOL 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
1706U32 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
1745void 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
1959static 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
2033void 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
2053ECursorType LLWindowSDL::getCursor()
2054{
2055 return mCurrentCursor;
2056}
2057
2058void 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
2106void 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
2128void 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
2139void LLWindowSDL::releaseMouse()
2140{
2141 // see LWindowSDL::captureMouse()
2142
2143 //llinfos << "LLWindowSDL::releaseMouse" << llendl;
2144}
2145
2146void 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
2163void 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
2180void LLWindowSDL::showCursorFromMouseMove()
2181{
2182 if (!mHideCursorPermanent)
2183 {
2184 showCursor();
2185 }
2186}
2187
2188void LLWindowSDL::hideCursorUntilMouseMove()
2189{
2190 if (!mHideCursorPermanent)
2191 {
2192 hideCursor();
2193 mHideCursorPermanent = FALSE;
2194 }
2195}
2196
2197
2198
2199//
2200// LLSplashScreenSDL
2201//
2202LLSplashScreenSDL::LLSplashScreenSDL()
2203{
2204}
2205
2206LLSplashScreenSDL::~LLSplashScreenSDL()
2207{
2208}
2209
2210void LLSplashScreenSDL::showImpl()
2211{
2212}
2213
2214void LLSplashScreenSDL::updateImpl(const char* mesg)
2215{
2216}
2217
2218
2219void LLSplashScreenSDL::hideImpl()
2220{
2221}
2222
2223
2224
2225#if LL_GTK
2226static 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
2236S32 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
2341static 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
2350BOOL 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
2425S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type)
2426{
2427 fprintf(stderr, "MSGBOX: %s: %s\n", caption, text);
2428 return 0;
2429}
2430
2431BOOL 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.
2439void 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
2483void shell_open( const char* file_path )
2484{
2485 // *FIX: (???)
2486 fprintf(stderr, "shell_open: %s\n", file_path);
2487}
2488
2489void *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
2500void 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
48class LLWindowSDL : public LLWindow
49{
50public:
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
116protected:
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
141protected:
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
181private:
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
201class LLSplashScreenSDL : public LLSplashScreen
202{
203public:
204 LLSplashScreenSDL();
205 virtual ~LLSplashScreenSDL();
206
207 /*virtual*/ void showImpl();
208 /*virtual*/ void updateImpl(const char* mesg);
209 /*virtual*/ void hideImpl();
210};
211
212S32 OSMessageBoxSDL(const char* text, const char* caption, U32 type);
213
214void load_url_external(const char* url);
215void 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
56const S32 WM_MOUSEWHEEL = 0x020A;
57const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */
58const S32 MAX_MESSAGE_PER_UPDATE = 20;
59const S32 BITS_PER_PIXEL = 32;
60const S32 MAX_NUM_RESOLUTIONS = 32;
61const F32 ICON_FLASH_TIME = 0.5f;
62
63extern BOOL gDebugWindowProc;
64
65LPWSTR gIconResource = IDI_APPLICATION;
66
67LLW32MsgCallback gAsyncMsgCallback = NULL;
68
69//
70// LLWindowWin32
71//
72
73void 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
97BOOL 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
131BOOL LLWindowWin32::sIsClassRegistered = FALSE;
132
133
134
135LPDIRECTINPUT8 g_pDI = NULL;
136LPDIRECTINPUTDEVICE8 g_pJoystick = NULL;
137BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
138 VOID* pContext );
139BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
140 VOID* pContext );
141
142
143LLWindowWin32::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
852LLWindowWin32::~LLWindowWin32()
853{
854 delete [] mWindowTitle;
855 mWindowTitle = NULL;
856
857 delete [] mSupportedResolutions;
858 mSupportedResolutions = NULL;
859
860 delete mWindowClassName;
861 mWindowClassName = NULL;
862}
863
864void LLWindowWin32::show()
865{
866 ShowWindow(mWindowHandle, SW_SHOW);
867 SetForegroundWindow(mWindowHandle);
868 SetFocus(mWindowHandle);
869}
870
871void LLWindowWin32::hide()
872{
873 setMouseClipping(FALSE);
874 ShowWindow(mWindowHandle, SW_HIDE);
875}
876
877void LLWindowWin32::minimize()
878{
879 setMouseClipping(FALSE);
880 showCursor();
881 ShowWindow(mWindowHandle, SW_MINIMIZE);
882}
883
884
885void 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()
895void 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
960BOOL LLWindowWin32::isValid()
961{
962 return (mWindowHandle != NULL);
963}
964
965BOOL LLWindowWin32::getVisible()
966{
967 return (mWindowHandle && IsWindowVisible(mWindowHandle));
968}
969
970BOOL LLWindowWin32::getMinimized()
971{
972 return (mWindowHandle && IsIconic(mWindowHandle));
973}
974
975BOOL LLWindowWin32::getMaximized()
976{
977 return (mWindowHandle && IsZoomed(mWindowHandle));
978}
979
980BOOL 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
997BOOL LLWindowWin32::getFullscreen()
998{
999 return mFullscreen;
1000}
1001
1002BOOL 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
1018BOOL 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
1034BOOL 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
1050BOOL 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
1063BOOL 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
1078BOOL 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
1559void 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
1573BOOL 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
1591BOOL 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
1608void 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
1618void 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
1629void LLWindowWin32::showCursorFromMouseMove()
1630{
1631 if (!mHideCursorPermanent)
1632 {
1633 showCursor();
1634 }
1635}
1636
1637void LLWindowWin32::hideCursorUntilMouseMove()
1638{
1639 if (!mHideCursorPermanent)
1640 {
1641 hideCursor();
1642 mHideCursorPermanent = FALSE;
1643 }
1644}
1645
1646BOOL LLWindowWin32::isCursorHidden()
1647{
1648 return mCursorHidden;
1649}
1650
1651
1652HCURSOR 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
1663void 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
1716void 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
1731ECursorType LLWindowWin32::getCursor()
1732{
1733 return mCurrentCursor;
1734}
1735
1736void LLWindowWin32::captureMouse()
1737{
1738 SetCapture(mWindowHandle);
1739}
1740
1741void LLWindowWin32::releaseMouse()
1742{
1743 ReleaseCapture();
1744}
1745
1746
1747void LLWindowWin32::delayInputProcessing()
1748{
1749 mInputProcessingPaused = TRUE;
1750}
1751
1752void 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
1801LRESULT 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
2279BOOL 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
2299BOOL 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
2318BOOL 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
2335BOOL 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
2352BOOL 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
2366BOOL 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
2381BOOL LLWindowWin32::isClipboardTextAvailable()
2382{
2383 return IsClipboardFormatAvailable(CF_UNICODETEXT) || IsClipboardFormatAvailable( CF_TEXT );
2384}
2385
2386
2387BOOL 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
2436BOOL 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.
2498void 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
2528BOOL 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
2558BOOL 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
2631S32 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
2637void 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
2649F32 LLWindowWin32::getGamma()
2650{
2651 return mCurrentGamma;
2652}
2653
2654BOOL LLWindowWin32::restoreGamma()
2655{
2656 return SetDeviceGammaRamp(mhDC, mPrevGammaRamp);
2657}
2658
2659BOOL 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
2682LLWindow::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
2725F32 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
2745F32 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
2760BOOL 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
2802BOOL 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
2815BOOL 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
2833void LLWindowWin32::swapBuffers()
2834{
2835 SwapBuffers(mhDC);
2836}
2837
2838
2839BOOL 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
2857BOOL 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
2878void 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//
2988LLSplashScreenWin32::LLSplashScreenWin32()
2989: mWindow(NULL)
2990{
2991}
2992
2993LLSplashScreenWin32::~LLSplashScreenWin32()
2994{
2995}
2996
2997void 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
3010void 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
3025void LLSplashScreenWin32::hideImpl()
3026{
3027 if (mWindow)
3028 {
3029 DestroyWindow(mWindow);
3030 mWindow = NULL;
3031 }
3032}
3033
3034
3035// static
3036LRESULT 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
3047S32 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
3094void 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
3187void 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
3206BOOL 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
3239void *LLWindowWin32::getPlatformWindow()
3240{
3241 return (void*)mWindowHandle;
3242}
3243
3244void LLWindowWin32::bringToFront()
3245{
3246 BringWindowToTop(mWindowHandle);
3247}
3248
3249// set (OS) window focus back to the client
3250void 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)
40typedef void (*LLW32MsgCallback)(const MSG &msg);
41
42class LLWindowWin32 : public LLWindow
43{
44public:
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
108protected:
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
136protected:
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
182class LLSplashScreenWin32 : public LLSplashScreen
183{
184public:
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
197private:
198#if LL_WINDOWS
199 HWND mWindow;
200#endif
201};
202
203extern LLW32MsgCallback gAsyncMsgCallback;
204
205static void handleMessage( const MSG& msg );
206
207S32 OSMessageBoxWin32(const char* text, const char* caption, U32 type);
208
209#endif //LL_LLWINDOWWIN32_H