aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpanellogin.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llpanellogin.cpp769
1 files changed, 769 insertions, 0 deletions
diff --git a/linden/indra/newview/llpanellogin.cpp b/linden/indra/newview/llpanellogin.cpp
new file mode 100644
index 0000000..3d3aee9
--- /dev/null
+++ b/linden/indra/newview/llpanellogin.cpp
@@ -0,0 +1,769 @@
1/**
2 * @file llpanellogin.cpp
3 * @brief Login dialog and logo display
4 *
5 * Copyright (c) 2002-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 "llviewerprecompiledheaders.h"
29
30#include "llpanellogin.h"
31#include "llpanelgeneral.h"
32
33#include "indra_constants.h" // for key and mask constants
34#include "llfontgl.h"
35#include "llmd5.h"
36#include "llsecondlifeurls.h"
37#include "llwindow.h" // shell_open()
38#include "llversion.h"
39#include "v4color.h"
40
41#include "llbutton.h"
42#include "llcheckboxctrl.h"
43#include "llcombobox.h"
44#include "llviewercontrol.h"
45#include "llfloaterabout.h"
46#include "llfloaterpreference.h"
47#include "llfocusmgr.h"
48#include "lllineeditor.h"
49#include "lltextbox.h"
50#include "llui.h"
51#include "lluiconstants.h"
52#include "llviewerbuild.h"
53#include "llviewerimagelist.h"
54#include "llviewermenu.h" // for handle_preferences()
55#include "llviewernetwork.h"
56#include "llviewerwindow.h" // to link into child list
57#include "llnotify.h"
58#include "viewer.h" // for gHideLinks
59#include "llvieweruictrlfactory.h"
60#include "llhttpclient.h"
61#include "llweb.h"
62#include "llwebbrowserctrl.h"
63
64#include "llfloaterhtmlhelp.h"
65#include "llfloatertos.h"
66
67#include "llglheaders.h"
68
69const S32 BLACK_BORDER_HEIGHT = 160;
70const S32 MAX_PASSWORD = 16;
71
72LLPanelLogin *LLPanelLogin::sInstance = NULL;
73BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
74
75// helper class that trys to download a URL from a web site and calls a method
76// on parent class indicating if the web server is working or not
77class LLIamHereLogin : public LLHTTPClient::Responder
78{
79 private:
80 LLIamHereLogin( LLPanelLogin* parent ) :
81 mParent( parent )
82 {}
83
84 LLPanelLogin* mParent;
85
86 public:
87 static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
88 {
89 return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
90 };
91
92 virtual void setParent( LLPanelLogin* parentIn )
93 {
94 mParent = parentIn;
95 };
96
97 virtual void result( const LLSD& content )
98 {
99 if ( mParent )
100 mParent->setSiteIsAlive( true );
101 };
102
103 virtual void error( U32 status, const std::string& reason )
104 {
105 if ( mParent )
106 mParent->setSiteIsAlive( false );
107 };
108};
109
110// this is global and not a class member to keep crud out of the header file
111namespace {
112 boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
113};
114
115//---------------------------------------------------------------------------
116// Public methods
117//---------------------------------------------------------------------------
118LLPanelLogin::LLPanelLogin(const LLRect &rect,
119 BOOL show_server,
120 void (*callback)(S32 option, void* user_data),
121 void *cb_data)
122: LLPanel("panel_login", LLRect(0,600,800,0), FALSE), // not bordered
123 mLogoImage(),
124 mCallback(callback),
125 mCallbackData(cb_data),
126 mHtmlAvailable( TRUE )
127{
128 mIsFocusRoot = TRUE;
129 mMungedPassword[0] = '\0';
130 mIncomingPassword[0] = '\0';
131
132 setBackgroundVisible(FALSE);
133 setBackgroundOpaque(TRUE);
134
135 // instance management
136 if (LLPanelLogin::sInstance)
137 {
138 llwarns << "Duplicate instance of login view deleted" << llendl;
139 delete LLPanelLogin::sInstance;
140 }
141
142 LLPanelLogin::sInstance = this;
143
144 // add to front so we are the bottom-most child
145 gViewerWindow->getRootView()->addChildAtEnd(this);
146
147 // Logo
148 mLogoImage = gImageList.getImage("startup_logo.tga", LLUUID::null, MIPMAP_FALSE, TRUE);
149
150 gUICtrlFactory->buildPanel(this, "panel_login.xml");
151 setRect(rect);
152 reshape(rect.getWidth(), rect.getHeight());
153
154 childSetPrevalidate("first_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
155 childSetPrevalidate("last_name_edit", LLLineEditor::prevalidatePrintableNoSpace);
156
157 childSetCommitCallback("password_edit", mungePassword);
158 childSetKeystrokeCallback("password_edit", onPassKey, this);
159 childSetUserData("password_edit", this);
160
161 LLLineEditor* edit = LLUICtrlFactory::getLineEditorByName(this, "password_edit");
162 if (edit) edit->setDrawAsterixes(TRUE);
163
164 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(this, "start_location_combo");
165 if (combo)
166 {
167 combo->setAllowTextEntry(TRUE, 128, FALSE);
168
169 // The XML file loads the combo with the following labels:
170 // 0 - "My Home"
171 // 1 - "My Last Location"
172 // 2 - "<Type region name>"
173
174 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
175 LLString sim_string = LLURLSimString::sInstance.mSimString;
176 if (!sim_string.empty())
177 {
178 // Replace "<Type region name>" with this region name
179 combo->remove(2);
180 combo->add( sim_string );
181 combo->setTextEntry(sim_string);
182 combo->setCurrentByIndex( 2 );
183 }
184 else if (login_last)
185 {
186 combo->setCurrentByIndex( 1 );
187 }
188 else
189 {
190 combo->setCurrentByIndex( 0 );
191 }
192
193 combo->setCommitCallback( &LLPanelGeneral::set_start_location );
194 }
195
196 // Specific servers added later.
197 childSetVisible("server_combo", show_server);
198
199 childSetAction("new_account_btn", onClickNewAccount, this);
200 childSetVisible("new_account_btn", !gHideLinks);
201
202 childSetAction("connect_btn", onClickConnect, this);
203
204 setDefaultBtn("connect_btn");
205
206 childSetAction("preferences_btn", LLFloaterPreference::show, this);
207
208 childSetAction("quit_btn", onClickQuit, this);
209
210 LLTextBox* text = LLUICtrlFactory::getTextBoxByName(this, "version_text");
211 if (text)
212 {
213 LLString version = llformat("%d.%d.%d (%d)",
214 LL_VERSION_MAJOR,
215 LL_VERSION_MINOR,
216 LL_VERSION_PATCH,
217 LL_VIEWER_BUILD );
218 text->setText(version);
219 text->setClickedCallback(onClickVersion);
220 text->setCallbackUserData(this);
221
222 // HACK
223 S32 right = getRect().mRight;
224 LLRect r = text->getRect();
225 const S32 PAD = 2;
226 r.setOriginAndSize( right - r.getWidth() - PAD, PAD,
227 r.getWidth(), r.getHeight() );
228 text->setRect(r);
229 }
230
231 // get the web browser control
232 #if LL_LIBXUL_ENABLED
233 LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(this, "login_html");
234 if ( web_browser )
235 {
236 // don't make it a tab stop until SL-27594 is fixed
237 web_browser->setTabStop(FALSE);
238
239 // painfully build the path to the loading screen
240 std::string loading_path( gDirUtilp->getExpandedFilename( LL_PATH_SKINS, "" ) );
241 loading_path.append( gDirUtilp->getDirDelimiter() );
242 loading_path.append( "html" );
243 loading_path.append( gDirUtilp->getDirDelimiter() );
244 loading_path.append( "loading" );
245 loading_path.append( gDirUtilp->getDirDelimiter() );
246 loading_path.append( "loading.html" );
247 web_browser->navigateTo( loading_path.c_str() );
248
249 // make links open in external browser
250 web_browser->setOpenInExternalBrowser( true );
251
252 // force the size to be correct (XML doesn't seem to be sufficient to do this) (with some padding so the other login screen doesn't show through)
253 LLRect htmlRect = mRect;
254 htmlRect.setCenterAndSize( mRect.getCenterX() - 2, mRect.getCenterY() + 40, mRect.getWidth() + 6, mRect.getHeight() - 78 );
255 web_browser->setRect( htmlRect );
256 web_browser->reshape( htmlRect.getWidth(), htmlRect.getHeight(), TRUE );
257 reshape( mRect.getWidth(), mRect.getHeight(), 1 );
258
259 // kick off a request to grab the url manually
260 gResponsePtr = LLIamHereLogin::build( this );
261 LLHTTPClient::get( childGetValue( "real_url" ).asString(), gResponsePtr );
262 };
263 #else
264 mHtmlAvailable = FALSE;
265 #endif
266
267 // Initialize visibility (and don't force visibility - use prefs)
268 refreshLocation( false );
269}
270
271void LLPanelLogin::setSiteIsAlive( bool alive )
272{
273#if LL_LIBXUL_ENABLED
274 LLWebBrowserCtrl* web_browser = LLUICtrlFactory::getWebBrowserCtrlByName(this, "login_html");
275 // if the contents of the site was retrieved
276 if ( alive )
277 {
278 if ( web_browser )
279 {
280 // navigate to the "real" page
281 web_browser->navigateTo( childGetValue( "real_url" ).asString() );
282
283 // mark as available
284 mHtmlAvailable = TRUE;
285 };
286 }
287 else
288 // the site is not available (missing page, server down, other badness)
289 {
290 if ( web_browser )
291 {
292 // hide browser control (revealing default one)
293 web_browser->setVisible( FALSE );
294
295 // mark as unavailable
296 mHtmlAvailable = FALSE;
297 };
298 };
299#else
300 mHtmlAvailable = FALSE;
301#endif
302}
303
304void LLPanelLogin::mungePassword(LLUICtrl* caller, void* user_data)
305{
306 LLPanelLogin* self = (LLPanelLogin*)user_data;
307 LLLineEditor* editor = (LLLineEditor*)caller;
308 std::string password = editor->getText();
309
310 // Re-md5 if we've changed at all
311 if (password != self->mIncomingPassword)
312 {
313 LLMD5 pass((unsigned char *)password.c_str());
314 pass.hex_digest(self->mMungedPassword);
315 }
316}
317
318LLPanelLogin::~LLPanelLogin()
319{
320 LLPanelLogin::sInstance = NULL;
321
322 // tell the responder we're not here anymore
323 if ( gResponsePtr )
324 gResponsePtr->setParent( 0 );
325
326 // We know we're done with the image, so be rid of it.
327 gImageList.deleteImage( mLogoImage );
328}
329
330// virtual
331void LLPanelLogin::draw()
332{
333 if (!getVisible()) return;
334
335 BOOL target_fullscreen;
336 S32 target_width;
337 S32 target_height;
338 gViewerWindow->getTargetWindow(target_fullscreen, target_width, target_height);
339
340 childSetVisible("full_screen_text", target_fullscreen);
341
342 glPushMatrix();
343 {
344 F32 image_aspect = 1.333333f;
345 F32 view_aspect = (F32)mRect.getWidth() / (F32)mRect.getHeight();
346 // stretch image to maintain aspect ratio
347 if (image_aspect > view_aspect)
348 {
349 glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * mRect.getWidth(), 0.f, 0.f);
350 glScalef(image_aspect / view_aspect, 1.f, 1.f);
351 }
352 // Don't maintain aspect ratio if screen wider than image. This results in the
353 // hand being partially cut off. JC
354 //else
355 //{
356 // glTranslatef(0.f, -0.5f * (view_aspect / image_aspect - 1.f) * (F32)BLACK_BORDER_HEIGHT, 0.f);
357 // glScalef(1.f, view_aspect / image_aspect, 1.f);
358 //}
359
360 S32 width = mRect.getWidth();
361 S32 height = mRect.getHeight();
362
363 if ( mHtmlAvailable )
364 {
365 // draw a background box in black
366 gl_rect_2d( 0, height - 264, width, 264, LLColor4( 0.0f, 0.0f, 0.0f, 1.f ) );
367
368 // draw the bottom part of the background image - just the blue background to the native client UI
369 gl_draw_scaled_image(0, -264, width + 8, mLogoImage->getHeight(), mLogoImage);
370 }
371 else
372 {
373 // the HTML login page is not available so default to the original screen
374 S32 offscreen_part = height / 3;
375 gl_draw_scaled_image(0, -offscreen_part, width, height+offscreen_part, mLogoImage);
376 };
377 }
378 glPopMatrix();
379
380 LLPanel::draw();
381}
382
383// virtual
384BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent)
385{
386 if (getVisible() && getEnabled())
387 {
388 if (( KEY_RETURN == key ) && (MASK_ALT == mask))
389 {
390 gViewerWindow->toggleFullscreen(FALSE);
391 return TRUE;
392 }
393
394 if (('P' == key) && (MASK_CONTROL == mask))
395 {
396 LLFloaterPreference::show(NULL);
397 return TRUE;
398 }
399
400 #if LL_LIBXUL_ENABLED
401 if ( KEY_F1 == key )
402 {
403 llinfos << "Spawning HTML help window" << llendl;
404 LLHtmlHelp::show( );
405 return TRUE;
406 };
407 #if ! LL_RELEASE_FOR_DOWNLOAD
408 if ( KEY_F2 == key )
409 {
410 llinfos << "Spawning floater TOS window" << llendl;
411 LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,"");
412 tos_dialog->startModal();
413 return TRUE;
414 };
415 #endif
416 #endif
417
418 if (!called_from_parent)
419 {
420 if (KEY_RETURN == key && MASK_NONE == mask)
421 {
422 // let the panel handle UICtrl processing: calls onClickConnect()
423 return LLPanel::handleKeyHere(key, mask, called_from_parent);
424 }
425 }
426 }
427
428 return LLPanel::handleKeyHere(key, mask, called_from_parent);
429}
430
431// virtual
432void LLPanelLogin::setFocus(BOOL b)
433{
434 if(b != hasFocus())
435 {
436 if(b)
437 {
438 LLPanelLogin::giveFocus();
439 }
440 else
441 {
442 LLPanel::setFocus(b);
443 }
444 }
445}
446
447// static
448void LLPanelLogin::giveFocus()
449{
450 if( sInstance )
451 {
452 // Grab focus and move cursor to first blank input field
453 std::string first = sInstance->childGetText("first_name_edit");
454 std::string pass = sInstance->childGetText("password_edit");
455
456 BOOL have_first = !first.empty();
457 BOOL have_pass = !pass.empty();
458
459 LLLineEditor* edit = NULL;
460 if (have_first && !have_pass)
461 {
462 // User saved his name but not his password. Move
463 // focus to password field.
464 edit = LLUICtrlFactory::getLineEditorByName(sInstance, "password_edit");
465 }
466 else
467 {
468 // User doesn't have a name, so start there.
469 edit = LLUICtrlFactory::getLineEditorByName(sInstance, "first_name_edit");
470 }
471
472 if (edit)
473 {
474 edit->setFocus(TRUE);
475 edit->selectAll();
476 }
477 }
478}
479
480
481// static
482void LLPanelLogin::show(const LLRect &rect,
483 BOOL show_server,
484 void (*callback)(S32 option, void* user_data),
485 void* callback_data)
486{
487 new LLPanelLogin(rect, show_server, callback, callback_data);
488
489 if( !gFocusMgr.getKeyboardFocus() )
490 {
491 // Grab focus and move cursor to first enabled control
492 sInstance->setFocus(TRUE);
493 // make sure that focus always goes here
494 gFocusMgr.setDefaultKeyboardFocus(sInstance);
495 }
496}
497
498// static
499void LLPanelLogin::setFields(const std::string& firstname, const std::string& lastname, const std::string& password,
500 BOOL remember)
501{
502 if (!sInstance)
503 {
504 llwarns << "Attempted fillFields with no login view shown" << llendl;
505 return;
506 }
507
508 sInstance->childSetText("first_name_edit", firstname);
509 sInstance->childSetText("last_name_edit", lastname);
510
511 // Max "actual" password length is 16 characters.
512 // Hex digests are always 32 characters.
513 if (password.length() == 32)
514 {
515 // This is a MD5 hex digest of a password.
516 // We don't actually use the password input field,
517 // fill it with MAX_PASSWORD characters so we get a
518 // nice row of asterixes.
519 const char* filler = "123456789!123456";
520 sInstance->childSetText("password_edit", filler);
521 strcpy(sInstance->mIncomingPassword, filler);
522 strcpy(sInstance->mMungedPassword, password.c_str());
523 }
524 else
525 {
526 // this is a normal text password
527 sInstance->childSetText("password_edit", password);
528 strcpy(sInstance->mIncomingPassword, password.c_str());
529 LLMD5 pass((unsigned char *)password.c_str());
530 pass.hex_digest(sInstance->mMungedPassword);
531 }
532
533 sInstance->childSetValue("remember_check", remember);
534}
535
536
537// static
538void LLPanelLogin::addServer(const char *server, S32 domain_name)
539{
540 if (!sInstance)
541 {
542 llwarns << "Attempted addServer with no login view shown" << llendl;
543 return;
544 }
545
546 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
547 if (combo)
548 {
549 combo->add(server, LLSD(domain_name) );
550 combo->setCurrentByIndex(0);
551 }
552}
553
554// static
555void LLPanelLogin::getFields(LLString &firstname, LLString &lastname, LLString &password,
556 BOOL &remember)
557{
558 if (!sInstance)
559 {
560 llwarns << "Attempted getFields with no login view shown" << llendl;
561 return;
562 }
563
564 firstname = sInstance->childGetText("first_name_edit");
565 LLString::trim(firstname);
566
567 lastname = sInstance->childGetText("last_name_edit");
568 LLString::trim(lastname);
569
570 password.assign( sInstance->mMungedPassword );
571 remember = sInstance->childGetValue("remember_check");
572}
573
574
575// static
576void LLPanelLogin::getServer(LLString &server, S32 &domain_name)
577{
578 if (!sInstance)
579 {
580 llwarns << "Attempted getServer with no login view shown" << llendl;
581 return;
582 }
583
584 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
585 if (combo)
586 {
587 LLSD combo_val = combo->getValue();
588 if (LLSD::TypeInteger == combo_val.type())
589 {
590 domain_name = combo->getValue().asInteger();
591
592 if ((S32)USERSERVER_OTHER == domain_name)
593 {
594 server = gUserServerName;
595 }
596 }
597 else
598 {
599 // no valid selection, return other
600 domain_name = (S32)USERSERVER_OTHER;
601 server = combo_val.asString();
602 }
603 }
604}
605
606// static
607void LLPanelLogin::getLocation(LLString &location)
608{
609 if (!sInstance)
610 {
611 llwarns << "Attempted getLocation with no login view shown" << llendl;
612 return;
613 }
614
615 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
616 if (combo)
617 {
618 location = combo->getValue().asString();
619 }
620}
621
622// static
623void LLPanelLogin::refreshLocation( bool force_visible )
624{
625 if (!sInstance) return;
626
627 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "start_location_combo");
628 if (!combo) return;
629
630 LLString sim_string = LLURLSimString::sInstance.mSimString;
631 if (!sim_string.empty())
632 {
633 combo->setCurrentByIndex( 3 ); // BUG? Maybe 2?
634 combo->setTextEntry(sim_string);
635 }
636 else
637 {
638 BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation");
639 combo->setCurrentByIndex( login_last ? 1 : 0 );
640 }
641
642 BOOL show_start = TRUE;
643
644 if ( ! force_visible )
645 show_start = gSavedSettings.getBOOL("ShowStartLocation");
646
647 sInstance->childSetVisible("start_location_combo", show_start);
648 sInstance->childSetVisible("start_location_text", show_start);
649}
650
651// static
652void LLPanelLogin::close()
653{
654 if (sInstance)
655 {
656 gViewerWindow->getRootView()->removeChild( LLPanelLogin::sInstance );
657
658 gFocusMgr.setDefaultKeyboardFocus(NULL);
659
660 delete sInstance;
661 sInstance = NULL;
662 }
663}
664
665
666//---------------------------------------------------------------------------
667// Protected methods
668//---------------------------------------------------------------------------
669
670// static
671void LLPanelLogin::onClickConnect(void *)
672{
673 if (sInstance && sInstance->mCallback)
674 {
675 // tell the responder we're not here anymore
676 if ( gResponsePtr )
677 gResponsePtr->setParent( 0 );
678
679 // JC - Make sure the fields all get committed.
680 sInstance->setFocus(FALSE);
681
682 LLString first = sInstance->childGetText("first_name_edit");
683 LLString last = sInstance->childGetText("last_name_edit");
684 if (!first.empty() && !last.empty())
685 {
686 // has both first and last name typed
687
688 // store off custom server entry, if currently selected
689 LLComboBox* combo = LLUICtrlFactory::getComboBoxByName(sInstance, "server_combo");
690 if (combo)
691 {
692 S32 selected_server = combo->getValue();
693 if (selected_server == USERSERVER_NONE)
694 {
695 LLString custom_server = combo->getValue().asString();
696 gSavedSettings.setString("CustomServer", custom_server);
697 }
698 }
699 sInstance->mCallback(0, sInstance->mCallbackData);
700 }
701 else
702 {
703 // empty first or last name
704 // same as clicking new account
705 onClickNewAccount(NULL);
706 }
707 }
708}
709
710
711// static
712void LLPanelLogin::newAccountAlertCallback(S32 option, void*)
713{
714 if (0 == option)
715 {
716 llinfos << "Going to account creation URL" << llendl;
717 LLWeb::loadURL( CREATE_ACCOUNT_URL );
718 }
719 else
720 {
721 sInstance->setFocus(TRUE);
722 }
723}
724
725
726// static
727void LLPanelLogin::onClickNewAccount(void*)
728{
729 if (gHideLinks)
730 {
731 gViewerWindow->alertXml("MustHaveAccountToLogInNoLinks");
732 }
733 else
734 {
735 gViewerWindow->alertXml("MustHaveAccountToLogIn",
736 LLPanelLogin::newAccountAlertCallback);
737 }
738}
739
740
741// static
742void LLPanelLogin::onClickQuit(void*)
743{
744 if (sInstance && sInstance->mCallback)
745 {
746 // tell the responder we're not here anymore
747 if ( gResponsePtr )
748 gResponsePtr->setParent( 0 );
749
750 sInstance->mCallback(1, sInstance->mCallbackData);
751 }
752}
753
754
755// static
756void LLPanelLogin::onClickVersion(void*)
757{
758 LLFloaterAbout::show(NULL);
759}
760
761// static
762void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
763{
764 if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
765 {
766 LLNotifyBox::showXml("CapsKeyOn");
767 sCapslockDidNotification = TRUE;
768 }
769}