llviewerwindow.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:146k
- /**
- * @file llviewerwindow.cpp
- * @brief Implementation of the LLViewerWindow class.
- *
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2010, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llviewerwindow.h"
- #if LL_WINDOWS
- #pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
- #endif
- // system library includes
- #include <stdio.h>
- #include <iostream>
- #include <fstream>
- #include <algorithm>
- #include "llfloaterreg.h"
- #include "llpanellogin.h"
- #include "llviewerkeyboard.h"
- #include "llviewermenu.h"
- #include "llviewquery.h"
- #include "llxmltree.h"
- #include "llslurl.h"
- //#include "llviewercamera.h"
- #include "llrender.h"
- #include "llvoiceclient.h" // for push-to-talk button handling
- //
- // TODO: Many of these includes are unnecessary. Remove them.
- //
- // linden library includes
- #include "llaudioengine.h" // mute on minimize
- #include "indra_constants.h"
- #include "llassetstorage.h"
- #include "llerrorcontrol.h"
- #include "llfontgl.h"
- #include "llmousehandler.h"
- #include "llrect.h"
- #include "llsky.h"
- #include "llstring.h"
- #include "llui.h"
- #include "lluuid.h"
- #include "llview.h"
- #include "llxfermanager.h"
- #include "message.h"
- #include "object_flags.h"
- #include "lltimer.h"
- #include "timing.h"
- #include "llviewermenu.h"
- #include "lltooltip.h"
- #include "llmediaentry.h"
- #include "llurldispatcher.h"
- #include "llurlsimstring.h"
- // newview includes
- #include "llagent.h"
- #include "llbox.h"
- #include "llconsole.h"
- #include "llviewercontrol.h"
- #include "llcylinder.h"
- #include "lldebugview.h"
- #include "lldir.h"
- #include "lldrawable.h"
- #include "lldrawpoolalpha.h"
- #include "lldrawpoolbump.h"
- #include "lldrawpoolwater.h"
- #include "llmaniptranslate.h"
- #include "llface.h"
- #include "llfeaturemanager.h"
- #include "llfilepicker.h"
- #include "llfloater.h"
- #include "llfloaterbuildoptions.h"
- #include "llfloaterbuyland.h"
- #include "llfloatercamera.h"
- #include "llfloatercustomize.h"
- #include "llfloaterland.h"
- #include "llfloaterinspect.h"
- #include "llfloatermap.h"
- #include "llfloaternamedesc.h"
- #include "llfloaterpreference.h"
- #include "llfloatersnapshot.h"
- #include "llfloatertools.h"
- #include "llfloaterworldmap.h"
- #include "llfocusmgr.h"
- #include "llfontfreetype.h"
- #include "llgesturemgr.h"
- #include "llglheaders.h"
- #include "lltooltip.h"
- #include "llhudmanager.h"
- #include "llhudview.h"
- #include "llimagebmp.h"
- #include "llimagej2c.h"
- #include "llimageworker.h"
- #include "llkeyboard.h"
- #include "lllineeditor.h"
- #include "llmenugl.h"
- #include "llmodaldialog.h"
- #include "llmorphview.h"
- #include "llmoveview.h"
- #include "llnavigationbar.h"
- #include "llpreviewtexture.h"
- #include "llprogressview.h"
- #include "llresmgr.h"
- #include "llsidetray.h"
- #include "llselectmgr.h"
- #include "llrootview.h"
- #include "llrendersphere.h"
- #include "llstartup.h"
- #include "llstatusbar.h"
- #include "llstatview.h"
- #include "llsurface.h"
- #include "llsurfacepatch.h"
- #include "lltexlayer.h"
- #include "lltextbox.h"
- #include "lltexturecache.h"
- #include "lltexturefetch.h"
- #include "lltextureview.h"
- #include "lltool.h"
- #include "lltoolcomp.h"
- #include "lltooldraganddrop.h"
- #include "lltoolface.h"
- #include "lltoolfocus.h"
- #include "lltoolgrab.h"
- #include "lltoolmgr.h"
- #include "lltoolmorph.h"
- #include "lltoolpie.h"
- #include "lltoolselectland.h"
- #include "lltrans.h"
- #include "lluictrlfactory.h"
- #include "llurldispatcher.h" // SLURL from other app instance
- #include "llvieweraudio.h"
- #include "llviewercamera.h"
- #include "llviewergesture.h"
- #include "llviewertexturelist.h"
- #include "llviewerinventory.h"
- #include "llviewerkeyboard.h"
- #include "llviewermedia.h"
- #include "llviewermediafocus.h"
- #include "llviewermenu.h"
- #include "llviewermessage.h"
- #include "llviewerobjectlist.h"
- #include "llviewerparcelmgr.h"
- #include "llviewerregion.h"
- #include "llviewershadermgr.h"
- #include "llviewerstats.h"
- #include "llvoavatarself.h"
- #include "llvovolume.h"
- #include "llworld.h"
- #include "llworldmapview.h"
- #include "pipeline.h"
- #include "llappviewer.h"
- #include "llviewerdisplay.h"
- #include "llspatialpartition.h"
- #include "llviewerjoystick.h"
- #include "llviewernetwork.h"
- #include "llpostprocess.h"
- #include "llbottomtray.h"
- #include "llnearbychatbar.h"
- #include "llagentui.h"
- #include "llwearablelist.h"
- #include "llnotifications.h"
- #include "llnotificationsutil.h"
- #include "llnotificationmanager.h"
- #include "llfloaternotificationsconsole.h"
- #include "llnearbychat.h"
- #include "llviewerwindowlistener.h"
- #if LL_WINDOWS
- #include <tchar.h> // For Unicode conversion methods
- #endif
- //
- // Globals
- //
- void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
- extern BOOL gDebugClicks;
- extern BOOL gDisplaySwapBuffers;
- extern BOOL gDepthDirty;
- extern BOOL gResizeScreenTexture;
- LLViewerWindow *gViewerWindow = NULL;
- LLFrameTimer gAwayTimer;
- LLFrameTimer gAwayTriggerTimer;
- BOOL gShowOverlayTitle = FALSE;
- LLViewerObject* gDebugRaycastObject = NULL;
- LLVector3 gDebugRaycastIntersection;
- LLVector2 gDebugRaycastTexCoord;
- LLVector3 gDebugRaycastNormal;
- LLVector3 gDebugRaycastBinormal;
- S32 gDebugRaycastFaceHit;
- // HUD display lines in lower right
- BOOL gDisplayWindInfo = FALSE;
- BOOL gDisplayCameraPos = FALSE;
- BOOL gDisplayFOV = FALSE;
- BOOL gDisplayBadge = FALSE;
- S32 CHAT_BAR_HEIGHT = 28;
- S32 OVERLAY_BAR_HEIGHT = 20;
- const U8 NO_FACE = 255;
- BOOL gQuietSnapshot = FALSE;
- const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
- const F32 MAX_FAST_FRAME_TIME = 0.5f;
- const F32 FAST_FRAME_INCREMENT = 0.1f;
- const F32 MIN_DISPLAY_SCALE = 0.75f;
- std::string LLViewerWindow::sSnapshotBaseName;
- std::string LLViewerWindow::sSnapshotDir;
- std::string LLViewerWindow::sMovieBaseName;
- class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole>
- {
- public:
- virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
- {
- //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
- // only log warnings to chat console
- //if (level == LLError::LEVEL_WARN)
- //{
- //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
- //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
- //{
- // LLChat chat;
- // chat.mText = message;
- // chat.mSourceType = CHAT_SOURCE_SYSTEM;
- // chat_floater->addChat(chat, FALSE, FALSE);
- //}
- //}
- }
- };
- ////////////////////////////////////////////////////////////////////////////
- //
- // LLDebugText
- //
- class LLDebugText
- {
- private:
- struct Line
- {
- Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
- std::string text;
- S32 x,y;
- };
- LLViewerWindow *mWindow;
-
- typedef std::vector<Line> line_list_t;
- line_list_t mLineList;
- LLColor4 mTextColor;
-
- public:
- LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-
- void addText(S32 x, S32 y, const std::string &text)
- {
- mLineList.push_back(Line(text, x, y));
- }
- void update()
- {
- std::string wind_vel_text;
- std::string wind_vector_text;
- std::string rwind_vel_text;
- std::string rwind_vector_text;
- std::string audio_text;
- // Draw the statistics in a light gray
- // and in a thin font
- mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
- // Draw stuff growing up from right lower corner of screen
- U32 xpos = mWindow->getWindowWidthScaled() - 350;
- U32 ypos = 64;
- const U32 y_inc = 20;
- if (gSavedSettings.getBOOL("DebugShowTime"))
- {
- const U32 y_inc2 = 15;
- for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
- iter != gDebugTimers.rend(); ++iter)
- {
- S32 idx = iter->first;
- LLFrameTimer& timer = iter->second;
- F32 time = timer.getElapsedTimeF32();
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- std::string label = gDebugTimerLabel[idx];
- if (label.empty()) label = llformat("Debug: %d", idx);
- addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
- }
-
- F32 time = gFrameTimeSeconds;
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
- }
-
- if (gDisplayCameraPos)
- {
- std::string camera_view_text;
- std::string camera_center_text;
- std::string agent_view_text;
- std::string agent_left_text;
- std::string agent_center_text;
- std::string agent_root_center_text;
- LLVector3d tvector; // Temporary vector to hold data for printing.
- // Update camera center, camera view, wind info every other frame
- tvector = gAgent.getPositionGlobal();
- agent_center_text = llformat("AgentCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- if (gAgent.getAvatarObject())
- {
- tvector = gAgent.getPosGlobalFromAgent(gAgent.getAvatarObject()->mRoot.getWorldPosition());
- agent_root_center_text = llformat("AgentRootCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- }
- else
- {
- agent_root_center_text = "---";
- }
- tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
- agent_view_text = llformat("AgentAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
- agent_left_text = llformat("AgentLeftAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- tvector = gAgent.getCameraPositionGlobal();
- camera_center_text = llformat("CameraCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
- camera_view_text = llformat("CameraAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- addText(xpos, ypos, agent_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_view_text); ypos += y_inc;
- addText(xpos, ypos, agent_left_text); ypos += y_inc;
- addText(xpos, ypos, camera_center_text); ypos += y_inc;
- addText(xpos, ypos, camera_view_text); ypos += y_inc;
- }
- if (gDisplayWindInfo)
- {
- wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
- wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
- rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
- rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
- addText(xpos, ypos, wind_vel_text); ypos += y_inc;
- addText(xpos, ypos, wind_vector_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
- }
- if (gDisplayWindInfo)
- {
- if (gAudiop)
- {
- audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
- }
- addText(xpos, ypos, audio_text); ypos += y_inc;
- }
- if (gDisplayFOV)
- {
- addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc;
- }
- if (gDisplayBadge)
- {
- addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc * 2;
- }
-
- /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- addText(xpos + 200, ypos, llformat("Flycam"));
- ypos += y_inc;
- }*/
-
- if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
- {
- if (gPipeline.getUseVertexShaders() == 0)
- {
- addText(xpos, ypos, "Shaders Disabled");
- ypos += y_inc;
- }
- addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
- ypos += y_inc;
- gPipeline.mTextureMatrixOps = 0;
- gPipeline.mMatrixOpCount = 0;
- if (gPipeline.mBatchCount > 0)
- {
- addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize,
- gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
- gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
- gPipeline.mMaxBatchSize = 0;
- gPipeline.mBatchCount = 0;
- }
- ypos += y_inc;
- addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
-
- ypos += y_inc;
- addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
-
- ypos += y_inc;
- addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
-
- ypos += y_inc;
- LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
- LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
- gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
- }
- if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
- {
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
- ypos += y_inc;
- addText(xpos, ypos, "Projection Matrix");
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
- ypos += y_inc;
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
- ypos += y_inc;
- addText(xpos, ypos, "View Matrix");
- ypos += y_inc;
- }
- if (gSavedSettings.getBOOL("DebugShowColor"))
- {
- U8 color[4];
- LLCoordGL coord = gViewerWindow->getCurrentMouse();
- glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
- addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
- ypos += y_inc;
- }
- // only display these messages if we are actually rendering beacons at this moment
- if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
- {
- if (LLPipeline::getRenderParticleBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing particle beacons (blue)");
- ypos += y_inc;
- }
- if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
- {
- addText(xpos, ypos, "Hiding particles");
- ypos += y_inc;
- }
- if (LLPipeline::getRenderPhysicalBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing physical object beacons (green)");
- ypos += y_inc;
- }
- if (LLPipeline::getRenderScriptedBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing scripted object beacons (red)");
- ypos += y_inc;
- }
- else
- if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing scripted object with touch function beacons (red)");
- ypos += y_inc;
- }
- if (LLPipeline::getRenderSoundBeacons(NULL))
- {
- addText(xpos, ypos, "Viewing sound beacons (yellow)");
- ypos += y_inc;
- }
- }
- }
- void draw()
- {
- for (line_list_t::iterator iter = mLineList.begin();
- iter != mLineList.end(); ++iter)
- {
- const Line& line = *iter;
- LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
- LLFontGL::LEFT, LLFontGL::TOP,
- LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
- }
- mLineList.clear();
- }
- };
- void LLViewerWindow::updateDebugText()
- {
- mDebugText->update();
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // LLViewerWindow
- //
- BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
- {
- const char* buttonname = "";
- const char* buttonstatestr = "";
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
- if (down)
- {
- buttonstatestr = "down" ;
- }
- else
- {
- buttonstatestr = "up" ;
- }
-
- switch (clicktype)
- {
- case LLMouseHandler::CLICK_LEFT:
- mLeftMouseDown = down;
- buttonname = "Left";
- break;
- case LLMouseHandler::CLICK_RIGHT:
- mRightMouseDown = down;
- buttonname = "Right";
- break;
- case LLMouseHandler::CLICK_MIDDLE:
- mMiddleMouseDown = down;
- buttonname = "Middle";
- break;
- case LLMouseHandler::CLICK_DOUBLELEFT:
- mLeftMouseDown = down;
- buttonname = "Left Double Click";
- break;
- }
-
- LLView::sMouseHandlerMessage.clear();
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
- if (gDebugClicks)
- {
- llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
- }
- // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
- if (down)
- mWindow->captureMouse();
- else
- mWindow->releaseMouse();
- // Indicate mouse was active
- LLUI::resetMouseIdleTimer();
- // Don't let the user move the mouse out of the window until mouse up.
- if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
- {
- mWindow->setMouseClipping(down);
- }
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
- }
- return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
- }
- // Topmost view gets a chance before the hierarchy
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x, local_y;
- top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- if (down)
- {
- if (top_ctrl->pointInView(local_x, local_y))
- {
- return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
- }
- else
- {
- gFocusMgr.setTopCtrl(NULL);
- }
- }
- else
- {
- if (top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask))
- {
- return TRUE;
- }
- }
- }
- // Give the UI views a chance to process the click
- if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
- }
- return TRUE;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
- }
- // Do not allow tool manager to handle mouseclicks if we have disconnected
- if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
- {
- return TRUE;
- }
-
- // If we got this far on a down-click, it wasn't handled.
- // Up-clicks, though, are always handled as far as the OS is concerned.
- BOOL default_rtn = !down;
- return default_rtn;
- }
- BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- BOOL down = TRUE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
- }
- BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- // try handling as a double-click first, then a single-click if that
- // wasn't handled.
- BOOL down = TRUE;
- if (handleAnyMouseClick(window, pos, mask,
- LLMouseHandler::CLICK_DOUBLELEFT, down))
- {
- return TRUE;
- }
- return handleMouseDown(window, pos, mask);
- }
- BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
- }
- BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
- BOOL down = TRUE;
- BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
- if (handle)
- return handle;
- // *HACK: this should be rolled into the composite tool logic, not
- // hardcoded at the top level.
- if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance())
- {
- // If the current tool didn't process the click, we should show
- // the pie menu. This can be done by passing the event to the pie
- // menu tool.
- LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
- // show_context_menu( x, y, mask );
- }
- return TRUE;
- }
- BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
- }
- BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- BOOL down = TRUE;
- gVoiceClient->middleMouseState(true);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
-
- // Always handled as far as the OS is concerned.
- return TRUE;
- }
- LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
- {
- LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
- const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
- const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
-
- if ( prim_media_dnd_enabled || slurl_dnd_enabled )
- {
- switch(action)
- {
- // Much of the handling for these two cases is the same.
- case LLWindowCallbacks::DNDA_TRACK:
- case LLWindowCallbacks::DNDA_DROPPED:
- case LLWindowCallbacks::DNDA_START_TRACKING:
- {
- bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
-
- if (slurl_dnd_enabled)
- {
- // special case SLURLs
- if ( LLSLURL::isSLURL( data ) )
- {
- if (drop)
- {
- LLURLDispatcher::dispatch( data, NULL, true );
- LLURLSimString::setStringRaw( LLSLURL::stripProtocol( data ) );
- LLPanelLogin::refreshLocation( true );
- LLPanelLogin::updateLocationUI();
- }
- return LLWindowCallbacks::DND_MOVE;
- };
- }
- if (prim_media_dnd_enabled)
- {
- LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ );
- LLUUID object_id = pick_info.getObjectID();
- S32 object_face = pick_info.mObjectFace;
- std::string url = data;
- lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl;
- LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
-
- if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
- {
- LLTextureEntry *te = obj->getTE(object_face);
- if (te)
- {
- if (drop)
- {
- // object does NOT have media already
- if ( ! te->hasMedia() )
- {
- // we are allowed to modify the object
- if ( obj->permModify() )
- {
- // Create new media entry
- LLSD media_data;
- // XXX Should we really do Home URL too?
- media_data[LLMediaEntry::HOME_URL_KEY] = url;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
- obj->syncMediaData(object_face, media_data, true, true);
- // XXX This shouldn't be necessary, should it ?!?
- if (obj->getMediaImpl(object_face))
- obj->getMediaImpl(object_face)->navigateReload();
- obj->sendMediaDataUpdate();
- result = LLWindowCallbacks::DND_COPY;
- }
- }
- else
- // object HAS media already
- {
- // URL passes the whitelist
- if (te->getMediaData()->checkCandidateUrl( url ) )
- {
- // we are allowed to modify the object or we have navigate permissions
- // NOTE: Design states you you can change the URL if you have media
- // navigate permissions even if you do not have prim modify rights
- if ( obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT ) )
- {
- // just navigate to the URL
- if (obj->getMediaImpl(object_face))
- {
- obj->getMediaImpl(object_face)->navigateTo(url);
- }
- else
- {
- // This is very strange. Navigation should
- // happen via the Impl, but we don't have one.
- // This sends it to the server, which /should/
- // trigger us getting it. Hopefully.
- LLSD media_data;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- obj->syncMediaData(object_face, media_data, true, true);
- obj->sendMediaDataUpdate();
- }
- result = LLWindowCallbacks::DND_LINK;
- }
- }
- }
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
-
- }
- else
- {
- // Check the whitelist, if there's media (otherwise just show it)
- if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
- {
- if ( obj != mDragHoveredObject)
- {
- // Highlight the dragged object
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = obj;
- LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
- }
- result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
- }
- }
- }
- }
- }
- }
- break;
-
- case LLWindowCallbacks::DNDA_STOP_TRACKING:
- // The cleanup case below will make sure things are unhilighted if necessary.
- break;
- }
- if (prim_media_dnd_enabled &&
- result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
- {
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
- }
- }
-
- return result;
- }
-
- BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- BOOL down = FALSE;
- gVoiceClient->middleMouseState(false);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
-
- // Always handled as far as the OS is concerned.
- return TRUE;
- }
- // WARNING: this is potentially called multiple times per frame
- void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
- {
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
- mMouseInWindow = TRUE;
- // Save mouse point for access during idle() and display()
- LLCoordGL mouse_point(x, y);
- if (mouse_point != mCurrentMousePoint)
- {
- LLUI::resetMouseIdleTimer();
- }
- saveLastMouse(mouse_point);
- mWindow->showCursorFromMouseMove();
- if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
- }
- void LLViewerWindow::handleMouseLeave(LLWindow *window)
- {
- // Note: we won't get this if we have captured the mouse.
- llassert( gFocusMgr.getMouseCapture() == NULL );
- mMouseInWindow = FALSE;
- LLToolTipMgr::instance().blockToolTips();
- }
- BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
- {
- // User has indicated they want to close, but we may need to ask
- // about modified documents.
- LLAppViewer::instance()->userQuit();
- // Don't quit immediately
- return FALSE;
- }
- void LLViewerWindow::handleQuit(LLWindow *window)
- {
- LLAppViewer::instance()->forceQuit();
- }
- void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
- {
- reshape(width, height);
- mResDirty = true;
- }
- // The top-level window has gained focus (e.g. via ALT-TAB)
- void LLViewerWindow::handleFocus(LLWindow *window)
- {
- gFocusMgr.setAppHasFocus(TRUE);
- LLModalDialog::onAppFocusGained();
- gAgent.onAppFocusGained();
- LLToolMgr::getInstance()->onAppFocusGained();
- // See if we're coming in with modifier keys held down
- if (gKeyboard)
- {
- gKeyboard->resetMaskKeys();
- }
- // resume foreground running timer
- // since we artifically limit framerate when not frontmost
- gForegroundTime.unpause();
- }
- // The top-level window has lost focus (e.g. via ALT-TAB)
- void LLViewerWindow::handleFocusLost(LLWindow *window)
- {
- gFocusMgr.setAppHasFocus(FALSE);
- //LLModalDialog::onAppFocusLost();
- LLToolMgr::getInstance()->onAppFocusLost();
- gFocusMgr.setMouseCapture( NULL );
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
- // restore mouse cursor
- showCursor();
- getWindow()->setMouseClipping(FALSE);
- // If losing focus while keys are down, reset them.
- if (gKeyboard)
- {
- gKeyboard->resetKeys();
- }
- // pause timer that tracks total foreground running time
- gForegroundTime.pause();
- }
- BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
- {
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- gVoiceClient->keyDown(key, mask);
-
- if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
- // *NOTE: We want to interpret KEY_RETURN later when it arrives as
- // a Unicode char, not as a keydown. Otherwise when client frame
- // rate is really low, hitting return sends your chat text before
- // it's all entered/processed.
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- return FALSE;
- }
- return gViewerKeyboard.handleKey(key, mask, repeated);
- }
- BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
- {
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- gVoiceClient->keyUp(key, mask);
- return FALSE;
- }
- void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
- {
- LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
- return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
- }
- BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
- {
- if (activated)
- {
- mActive = TRUE;
- send_agent_resume();
- gAgent.clearAFK();
- if (mWindow->getFullscreen() && !mIgnoreActivate)
- {
- if (!LLApp::isExiting() )
- {
- if (LLStartUp::getStartupState() >= STATE_STARTED)
- {
- // if we're in world, show a progress bar to hide reloading of textures
- llinfos << "Restoring GL during activate" << llendl;
- restoreGL("Restoring...");
- }
- else
- {
- // otherwise restore immediately
- restoreGL();
- }
- }
- else
- {
- llwarns << "Activating while quitting" << llendl;
- }
- }
- // Unmute audio
- audio_update_volume();
- }
- else
- {
- mActive = FALSE;
-
- if (gSavedSettings.getS32("AFKTimeout"))
- {
- gAgent.setAFK();
- }
-
- // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
- if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK)
- {
- gAgent.changeCameraToDefault();
- }
-
- send_agent_pause();
-
- if (mWindow->getFullscreen() && !mIgnoreActivate)
- {
- llinfos << "Stopping GL during deactivation" << llendl;
- stopGL();
- }
- // Mute audio
- audio_update_volume();
- }
- return TRUE;
- }
- BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
- {
- //if (!activating) gAgent.changeCameraToDefault();
- LLViewerJoystick::getInstance()->setNeedsReset(true);
- return FALSE;
- }
- void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
- {
- }
- BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
- {
- #if LL_WINDOWS
- if (gNoRender)
- {
- HWND window_handle = (HWND)window->getPlatformWindow();
- PAINTSTRUCT ps;
- HDC hdc;
-
- RECT wnd_rect;
- wnd_rect.left = 0;
- wnd_rect.top = 0;
- wnd_rect.bottom = 200;
- wnd_rect.right = 500;
- hdc = BeginPaint(window_handle, &ps);
- //SetBKColor(hdc, RGB(255, 255, 255));
- FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
- std::string name_str;
- LLAgentUI::buildName(name_str);
- std::string temp_str;
- temp_str = llformat( "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
- name_str.c_str(),
- LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),
- LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),
- LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0));
- S32 len = temp_str.length();
- TextOutA(hdc, 0, 0, temp_str.c_str(), len);
- LLVector3d pos_global = gAgent.getPositionGlobal();
- temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
- len = temp_str.length();
- TextOutA(hdc, 0, 25, temp_str.c_str(), len);
- TextOutA(hdc, 0, 50, "Set "DisableRendering FALSE" in settings.ini file to reenable", 61);
- EndPaint(window_handle, &ps);
- return TRUE;
- }
- #endif
- return FALSE;
- }
- void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
- {
- handleScrollWheel( clicks );
- }
- void LLViewerWindow::handleWindowBlock(LLWindow *window)
- {
- send_agent_pause();
- }
- void LLViewerWindow::handleWindowUnblock(LLWindow *window)
- {
- send_agent_resume();
- }
- void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
- {
- const S32 SLURL_MESSAGE_TYPE = 0;
- switch (data_type)
- {
- case SLURL_MESSAGE_TYPE:
- // received URL
- std::string url = (const char*)data;
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- if (LLURLDispatcher::dispatch(url, web, trusted_browser))
- {
- // bring window to foreground, as it has just been "launched" from a URL
- mWindow->bringToFront();
- }
- break;
- }
- }
- BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
- {
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- LLViewerJoystick::getInstance()->updateStatus();
- return TRUE;
- }
- return FALSE;
- }
- BOOL LLViewerWindow::handleDeviceChange(LLWindow *window)
- {
- // give a chance to use a joystick after startup (hot-plugging)
- if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
- {
- LLViewerJoystick::getInstance()->init(true);
- return TRUE;
- }
- return FALSE;
- }
- void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
- {
- LLAppViewer::instance()->pingMainloopTimeout(msg);
- }
- void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
- {
- LLAppViewer::instance()->resumeMainloopTimeout();
- }
- void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
- {
- LLAppViewer::instance()->pauseMainloopTimeout();
- }
- //virtual
- std::string LLViewerWindow::translateString(const char* tag)
- {
- return LLTrans::getString( std::string(tag) );
- }
- //virtual
- std::string LLViewerWindow::translateString(const char* tag,
- const std::map<std::string, std::string>& args)
- {
- // LLTrans uses a special subclass of std::string for format maps,
- // but we must use std::map<> in these callbacks, otherwise we create
- // a dependency between LLWindow and LLFormatMapString. So copy the data.
- LLStringUtil::format_map_t args_copy;
- std::map<std::string,std::string>::const_iterator it = args.begin();
- for ( ; it != args.end(); ++it)
- {
- args_copy[it->first] = it->second;
- }
- return LLTrans::getString( std::string(tag), args_copy);
- }
- //
- // Classes
- //
- LLViewerWindow::LLViewerWindow(
- const std::string& title, const std::string& name,
- S32 x, S32 y,
- S32 width, S32 height,
- BOOL fullscreen, BOOL ignore_pixel_depth)
- :
- mWindow(NULL),
- mActive(TRUE),
- mWantFullscreen(fullscreen),
- mShowFullscreenProgress(FALSE),
- mWindowRectRaw(0, height, width, 0),
- mWindowRectScaled(0, height, width, 0),
- mWorldViewRectRaw(0, height, width, 0),
- mLeftMouseDown(FALSE),
- mMiddleMouseDown(FALSE),
- mRightMouseDown(FALSE),
- mMouseInWindow( FALSE ),
- mLastMask( MASK_NONE ),
- mToolStored( NULL ),
- mHideCursorPermanent( FALSE ),
- mCursorHidden(FALSE),
- mIgnoreActivate( FALSE ),
- mResDirty(false),
- mStatesDirty(false),
- mIsFullscreenChecked(false),
- mCurrResolutionIndex(0),
- mViewerWindowListener(new LLViewerWindowListener(this))
- {
- LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
- LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
- LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert);
- LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert);
- LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications"));
- llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl;
- // Default to application directory.
- LLViewerWindow::sSnapshotBaseName = "Snapshot";
- LLViewerWindow::sMovieBaseName = "SLmovie";
- resetSnapshotLoc();
- // create window
- mWindow = LLWindowManager::createWindow(this,
- title, name, x, y, width, height, 0,
- fullscreen,
- gNoRender,
- gSavedSettings.getBOOL("DisableVerticalSync"),
- !gNoRender,
- ignore_pixel_depth,
- gSavedSettings.getU32("RenderFSAASamples"));
- if (!LLAppViewer::instance()->restoreErrorTrap())
- {
- LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
- }
- if (NULL == mWindow)
- {
- LLSplashScreen::update("Shutting down...");
- #if LL_LINUX || LL_SOLARIS
- llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information."
- << llendl;
- #else
- LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
- << LL_ENDL;
- #endif
- LLAppViewer::instance()->forceExit(1);
- }
-
- // Get the real window rect the window was created with (since there are various OS-dependent reasons why
- // the size of a window or fullscreen context may have been adjusted slightly...)
- F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
-
- mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- mDisplayScale *= ui_scale_factor;
- LLUI::setScaleFactor(mDisplayScale);
- {
- LLCoordWindow size;
- mWindow->getSize(&size);
- mWindowRectRaw.set(0, size.mY, size.mX, 0);
- mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
- }
-
- LLFontManager::initClass();
- //
- // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
- // stuff like AGP if we think that it'll crash the viewer.
- //
- LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
- LLFeatureManager::getInstance()->init();
- // Initialize OpenGL Renderer
- if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
- !gGLManager.mHasVertexBufferObject)
- {
- gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
- }
- LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"));
- if (LLFeatureManager::getInstance()->isSafe()
- || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
- || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
- {
- LLFeatureManager::getInstance()->applyRecommendedSettings();
- gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
- }
- // If we crashed while initializng GL stuff last time, disable certain features
- if (gSavedSettings.getBOOL("RenderInitError"))
- {
- mInitAlert = "DisplaySettingsNoShaders";
- LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
- gSavedSettings.setU32("RenderQualityPerformance", 0);
- }
-
- // Init the image list. Must happen after GL is initialized and before the images that
- // LLViewerWindow needs are requested.
- LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
- gTextureList.init();
- LLViewerTextureManager::init() ;
- gBumpImageList.init();
-
- // Init font system, but don't actually load the fonts yet
- // because our window isn't onscreen and they take several
- // seconds to parse.
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX],
- mDisplayScale.mV[VY],
- gDirUtilp->getAppRODataDir(),
- LLUI::getXUIPaths());
-
- // Create container for all sub-views
- LLView::Params rvp;
- rvp.name("root");
- rvp.rect(mWindowRectScaled);
- rvp.mouse_opaque(false);
- rvp.follows.flags(FOLLOWS_NONE);
- mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
- LLUI::setRootView(mRootView);
- // Make avatar head look forward at start
- mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
- mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
- gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
- mOverlayTitle = gSavedSettings.getString("OverlayTitle");
- // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
- LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
- // sync the keyboard's setting with the saved setting
- gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
- mDebugText = new LLDebugText(this);
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
- }
- void LLViewerWindow::initGLDefaults()
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
- F32 ambient[4] = {0.f,0.f,0.f,0.f };
- F32 diffuse[4] = {1.f,1.f,1.f,1.f };
- glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
- glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
-
- glPixelStorei(GL_PACK_ALIGNMENT,1);
- glPixelStorei(GL_UNPACK_ALIGNMENT,1);
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- // lights for objects
- glShadeModel( GL_SMOOTH );
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
-
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
- glCullFace(GL_BACK);
- // RN: Need this for translation and stretch manip.
- gCone.prerender();
- gBox.prerender();
- gSphere.prerender();
- gCylinder.prerender();
- }
- struct MainPanel : public LLPanel
- {
- };
- void LLViewerWindow::initBase()
- {
- S32 height = getWindowHeightScaled();
- S32 width = getWindowWidthScaled();
- LLRect full_window(0, height, width, 0);
- ////////////////////
- //
- // Set the gamma
- //
- F32 gamma = gSavedSettings.getF32("RenderGamma");
- if (gamma != 0.0f)
- {
- getWindow()->setGamma(gamma);
- }
- // Create global views
- // Create the floater view at the start so that other views can add children to it.
- // (But wait to add it as a child of the root view so that it will be in front of the
- // other views.)
- MainPanel* main_view = new MainPanel();
- LLUICtrlFactory::instance().buildPanel(main_view, "main_view.xml");
- main_view->setShape(full_window);
- getRootView()->addChild(main_view);
- // placeholder widget that controls where "world" is rendered
- mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
- mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
- mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
- // Constrain floaters to inside the menu and status bar regions.
- gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
- gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
-
- // Console
- llassert( !gConsole );
- LLConsole::Params cp;
- cp.name("console");
- cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
- cp.rect(getChatConsoleRect());
- cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
- cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
- cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
- gConsole = LLUICtrlFactory::create<LLConsole>(cp);
- getRootView()->addChild(gConsole);
- // optionally forward warnings to chat console/chat floater
- // for qa runs and dev builds
- #if !LL_RELEASE_FOR_DOWNLOAD
- LLError::addRecorder(RecordToChatConsole::getInstance());
- #else
- if(gSavedSettings.getBOOL("QAMode"))
- {
- LLError::addRecorder(RecordToChatConsole::getInstance());
- }
- #endif
- gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
- gDebugView->init();
- gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
- // Add the progress bar view (startup view), which overrides everything
- mProgressView = new LLProgressView(full_window);
- getRootView()->addChild(mProgressView);
- setShowProgress(FALSE);
- setProgressCancelButtonVisible(FALSE);
- gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
- LLMenuGL::sMenuContainer = gMenuHolder;
- }
- void LLViewerWindow::initWorldUI()
- {
- S32 height = mRootView->getRect().getHeight();
- S32 width = mRootView->getRect().getWidth();
- LLRect full_window(0, height, width, 0);
- gIMMgr = LLIMMgr::getInstance();
- getRootView()->sendChildToFront(gFloaterView);
- getRootView()->sendChildToFront(gSnapshotFloaterView);
- // new bottom panel
- LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container");
- LLBottomTray* bottom_tray = LLBottomTray::getInstance();
- bottom_tray->setShape(bottom_tray_container->getLocalRect());
- bottom_tray->setFollowsAll();
- bottom_tray_container->addChild(bottom_tray);
- bottom_tray_container->setVisible(TRUE);
- LLRect morph_view_rect = full_window;
- morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
- morph_view_rect.mTop = full_window.mTop - 32;
- LLMorphView::Params mvp;
- mvp.name("MorphView");
- mvp.rect(morph_view_rect);
- mvp.visible(false);
- gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
- getRootView()->addChild(gMorphView);
- LLWorldMapView::initClass();
-
- // Force gFloaterWorldMap to initialize
- LLFloaterReg::getInstance("world_map");
- // Force gFloaterTools to initialize
- LLFloaterReg::getInstance("build");
- LLFloaterReg::hideInstance("build");
- // Status bar
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
- gStatusBar->setFollowsAll();
- gStatusBar->setShape(status_bar_container->getLocalRect());
- // sync bg color with menu bar
- gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() );
- status_bar_container->addChild(gStatusBar);
- status_bar_container->setVisible(TRUE);
- // Navigation bar
- LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container");
- LLNavigationBar* navbar = LLNavigationBar::getInstance();
- navbar->setShape(nav_bar_container->getLocalRect());
- navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
- nav_bar_container->addChild(navbar);
- nav_bar_container->setVisible(TRUE);
-
- if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
- {
- navbar->showNavigationPanel(FALSE);
- }
- if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"))
- {
- navbar->showFavoritesPanel(FALSE);
- }
- if (!gSavedSettings.getBOOL("ShowCameraButton"))
- {
- LLBottomTray::getInstance()->showCameraButton(FALSE);
- }
- if (!gSavedSettings.getBOOL("ShowSnapshotButton"))
- {
- LLBottomTray::getInstance()->showSnapshotButton(FALSE);
- }
- if (!gSavedSettings.getBOOL("ShowMoveButton"))
- {
- LLBottomTray::getInstance()->showMoveButton(FALSE);
- }
- if (!gSavedSettings.getBOOL("ShowGestureButton"))
- {
- LLBottomTray::getInstance()->showGestureButton(FALSE);
- }
- if ( gHUDView == NULL )
- {
- LLRect hud_rect = full_window;
- hud_rect.mBottom += 50;
- if (gMenuBarView)
- {
- hud_rect.mTop -= gMenuBarView->getRect().getHeight();
- }
- gHUDView = new LLHUDView(hud_rect);
- // put behind everything else in the UI
- getRootView()->addChildInBack(gHUDView);
- }
- LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container");
- LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
- panel_ssf_container->addChild(panel_stand_stop_flying);
- panel_ssf_container->setVisible(TRUE);
- // put sidetray in container
- LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container");
- LLSideTray* sidetrayp = LLSideTray::getInstance();
- sidetrayp->setShape(side_tray_container->getLocalRect());
- // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout
- sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
- side_tray_container->addChild(sidetrayp);
- side_tray_container->setVisible(FALSE);
-
- // put sidetray buttons in their own panel
- LLPanel* buttons_panel = sidetrayp->getButtonsPanel();
- LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs");
- buttons_panel->setShape(buttons_panel_container->getLocalRect());
- buttons_panel->setFollowsAll();
- buttons_panel_container->addChild(buttons_panel);
- }
- // Destroy the UI
- void LLViewerWindow::shutdownViews()
- {
- // clean up warning logger
- LLError::removeRecorder(RecordToChatConsole::getInstance());
- delete mDebugText;
- mDebugText = NULL;
-
- // Cleanup global views
- if (gMorphView)
- {
- gMorphView->setVisible(FALSE);
- }
- // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
- // will crump with LL_ERRS.
- LLModalDialog::shutdownModals();
-
- // destroy the nav bar, not currently part of gViewerWindow
- // *TODO: Make LLNavigationBar part of gViewerWindow
- delete LLNavigationBar::getInstance();
- // destroy menus after instantiating navbar above, as it needs
- // access to gMenuHolder
- cleanup_menus();
- // Delete all child views.
- delete mRootView;
- mRootView = NULL;
- // Automatically deleted as children of mRootView. Fix the globals.
- gStatusBar = NULL;
- gIMMgr = NULL;
- gToolTipView = NULL;
- gFloaterView = NULL;
- gMorphView = NULL;
- gHUDView = NULL;
- }
- void LLViewerWindow::shutdownGL()
- {
- //--------------------------------------------------------
- // Shutdown GL cleanly. Order is very important here.
- //--------------------------------------------------------
- LLFontGL::destroyDefaultFonts();
- LLFontManager::cleanupClass();
- stop_glerror();
- gSky.cleanup();
- stop_glerror();
- LLWearableList::instance().cleanup() ;
- gTextureList.shutdown();
- stop_glerror();
- gBumpImageList.shutdown();
- stop_glerror();
- LLWorldMapView::cleanupTextures();
- llinfos << "Cleaning up pipeline" << llendl;
- gPipeline.cleanup();
- stop_glerror();
- LLViewerTextureManager::cleanup() ;
- LLImageGL::cleanupClass() ;
- llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
- llinfos << "Cleaning up select manager" << llendl;
- LLSelectMgr::getInstance()->cleanup();
- LLVertexBuffer::cleanupClass();
- llinfos << "Stopping GL during shutdown" << llendl;
- if (!gNoRender)
- {
- stopGL(FALSE);
- stop_glerror();
- }
- gGL.shutdown();
- }
- // shutdownViews() and shutdownGL() need to be called first
- LLViewerWindow::~LLViewerWindow()
- {
- llinfos << "Destroying Window" << llendl;
- destroyWindow();
- delete mDebugText;
- mDebugText = NULL;
- }
- void LLViewerWindow::setCursor( ECursorType c )
- {
- mWindow->setCursor( c );
- }
- void LLViewerWindow::showCursor()
- {
- mWindow->showCursor();
-
- mCursorHidden = FALSE;
- }
- void LLViewerWindow::hideCursor()
- {
- // And hide the cursor
- mWindow->hideCursor();
- mCursorHidden = TRUE;
- }
- void LLViewerWindow::sendShapeToSim()
- {
- LLMessageSystem* msg = gMessageSystem;
- if(!msg) return;
- msg->newMessageFast(_PREHASH_AgentHeightWidth);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
- msg->nextBlockFast(_PREHASH_HeightWidthBlock);
- msg->addU32Fast(_PREHASH_GenCounter, 0);
- U16 height16 = (U16) mWorldViewRectRaw.getHeight();
- U16 width16 = (U16) mWorldViewRectRaw.getWidth();
- msg->addU16Fast(_PREHASH_Height, height16);
- msg->addU16Fast(_PREHASH_Width, width16);
- gAgent.sendReliableMessage();
- }
- // Must be called after window is created to set up agent
- // camera variables and UI variables.
- void LLViewerWindow::reshape(S32 width, S32 height)
- {
- // Destroying the window at quit time generates spurious
- // reshape messages. We don't care about these, and we
- // don't want to send messages because the message system
- // may have been destructed.
- if (!LLApp::isExiting())
- {
- if (gNoRender)
- {
- return;
- }
- // update our window rectangle
- mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
- mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
- //glViewport(0, 0, width, height );
- if (height > 0)
- {
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
- }
- calcDisplayScale();
-
- BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
- LLUI::setScaleFactor(mDisplayScale);
- // update our window rectangle
- mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
- mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
- setup2DViewport();
- // Inform lower views of the change
- // round up when converting coordinates to make sure there are no gaps at edge of window
- LLView::sForceReshape = display_scale_changed;
- mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
- LLView::sForceReshape = FALSE;
- // clear font width caches
- if (display_scale_changed)
- {
- LLHUDText::reshape();
- }
- sendShapeToSim();
- // store the mode the user wants (even if not there yet)
- gSavedSettings.setBOOL("WindowFullScreen", mWantFullscreen);
- // store new settings for the mode we are in, regardless
- if (!mWindow->getFullscreen())
- {
- // Only save size if not maximized
- BOOL maximized = mWindow->getMaximized();
- gSavedSettings.setBOOL("WindowMaximized", maximized);
- LLCoordScreen window_size;
- if (!maximized
- && mWindow->getSize(&window_size))
- {
- gSavedSettings.setS32("WindowWidth", window_size.mX);
- gSavedSettings.setS32("WindowHeight", window_size.mY);
- }
- }
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
- }
- }
- // Hide normal UI when a logon fails
- void LLViewerWindow::setNormalControlsVisible( BOOL visible )
- {
- if(LLBottomTray::instanceExists())
- {
- LLBottomTray::getInstance()->setVisible(visible);
- LLBottomTray::getInstance()->setEnabled(visible);
- }
- if ( gMenuBarView )
- {
- gMenuBarView->setVisible( visible );
- gMenuBarView->setEnabled( visible );
- // ...and set the menu color appropriately.
- setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
- LLViewerLogin::getInstance()->isInProductionGrid());
- }
-
- if ( gStatusBar )
- {
- gStatusBar->setVisible( visible );
- gStatusBar->setEnabled( visible );
- }
-
- LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar");
- if (navbarp)
- {
- navbarp->setVisible( visible );
- }
- }
- void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
- {
- LLSD args;
- LLColor4 new_bg_color;
- if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
- }
- else if(god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
- }
- else if(!god_mode && !LLViewerLogin::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
- }
- else
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
- }
- if(gMenuBarView)
- {
- gMenuBarView->setBackgroundColor( new_bg_color );
- }
- if(gStatusBar)
- {
- gStatusBar->setBackgroundColor( new_bg_color );
- }
- }
- void LLViewerWindow::drawDebugText()
- {
- gGL.color4f(1,1,1,1);
- gGL.pushMatrix();
- {
- // scale view by UI global scale factor and aspect ratio correction factor
- glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
- mDebugText->draw();
- }
- gGL.popMatrix();
- gGL.flush();
- }
- void LLViewerWindow::draw()
- {
-
- #if LL_DEBUG
- LLView::sIsDrawing = TRUE;
- #endif
- stop_glerror();
-
- LLUI::setLineWidth(1.f);
- LLUI::setLineWidth(1.f);
- // Reset any left-over transforms
- glMatrixMode(GL_MODELVIEW);
-
- glLoadIdentity();
- //S32 screen_x, screen_y;
- if (!gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- LLUI::sDirtyRect = getWindowRectScaled();
- }
- // HACK for timecode debugging
- if (gSavedSettings.getBOOL("DisplayTimecode"))
- {
- // draw timecode block
- std::string text;
- glLoadIdentity();
- microsecondsToTimecodeString(gFrameTime,text);
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- font->renderUTF8(text, 0,
- llround((getWindowWidthScaled()/2)-100.f),
- llround((getWindowHeightScaled()-60.f)),
- LLColor4( 1.f, 1.f, 1.f, 1.f ),
- LLFontGL::LEFT, LLFontGL::TOP);
- }
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
- gGL.pushMatrix();
- {
- // scale view by UI global scale factor and aspect ratio correction factor
- glScalef(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
- LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
- // apply camera zoom transform (for high res screenshots)
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x,
- (F32)getWindowHeightScaled() * -(F32)pos_y,
- 0.f);
- glScalef(zoom_factor, zoom_factor, 1.f);
- LLUI::sGLScaleFactor *= zoom_factor;
- }
- // Draw tool specific overlay on world
- LLToolMgr::getInstance()->getCurrentTool()->draw();
- if( gAgent.cameraMouselook() )
- {
- drawMouselookInstructions();
- stop_glerror();
- }
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
- mRootView->draw();
- if (LLView::sDebugRects)
- {
- gToolTipView->drawStickyRect();
- }
- // Draw optional on-top-of-everyone view
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl && top_ctrl->getVisible())
- {
- S32 screen_x, screen_y;
- top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
- glMatrixMode(GL_MODELVIEW);
- LLUI::pushMatrix();
- LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
- top_ctrl->draw();
- LLUI::popMatrix();
- }
- if( gShowOverlayTitle && !mOverlayTitle.empty() )
- {
- // Used for special titles such as "Second Life - Special E3 2003 Beta"
- const S32 DIST_FROM_TOP = 20;
- LLFontGL::getFontSansSerifBig()->renderUTF8(
- mOverlayTitle, 0,
- llround( getWindowWidthScaled() * 0.5f),
- getWindowHeightScaled() - DIST_FROM_TOP,
- LLColor4(1, 1, 1, 0.4f),
- LLFontGL::HCENTER, LLFontGL::TOP);
- }
- LLUI::sGLScaleFactor = old_scale_factor;
- }
- gGL.popMatrix();
- #if LL_DEBUG
- LLView::sIsDrawing = FALSE;
- #endif
- }
- // Takes a single keydown event, usually when UI is visible
- BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
- {
- if (gFocusMgr.getKeyboardFocus()
- && !(mask & (MASK_CONTROL | MASK_ALT))
- && !gFocusMgr.getKeystrokesOnly())
- {
- // We have keyboard focus, and it's not an accelerator
- if (key < 0x80)
- {
- // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
- return (gFocusMgr.getKeyboardFocus() != NULL);
- }
- }
- // hide tooltips on keypress
- LLToolTipMgr::instance().blockToolTips();
-
- // Explicit hack for debug menu.
- if ((MASK_ALT & mask) &&
- (MASK_CONTROL & mask) &&
- ('D' == key || 'd' == key))
- {
- toggle_debug_menus(NULL);
- }
- // Explicit hack for debug menu.
- if ((mask == (MASK_SHIFT | MASK_CONTROL)) &&
- ('G' == key || 'g' == key))
- {
- if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) //on splash page
- {
- BOOL visible = ! gSavedSettings.getBOOL("ForceShowGrid");
- gSavedSettings.setBOOL("ForceShowGrid", visible);
- // Initialize visibility (and don't force visibility - use prefs)
- LLPanelLogin::refreshLocation( false );
- }
- }
- // Debugging view for unified notifications: CTRL-SHIFT-5
- // *FIXME: Having this special-cased right here (just so this can be invoked from the login screen) sucks.
- if ((MASK_SHIFT & mask)
- && (!(MASK_ALT & mask))
- && (MASK_CONTROL & mask)
- && ('5' == key))
- {
- //LLFloaterNotificationConsole::showInstance();
- LLFloaterReg::showInstance("notifications_console");
- return TRUE;
- }
- // handle escape key
- //if (key == KEY_ESCAPE && mask == MASK_NONE)
- //{
- // *TODO: get this to play well with mouselook and hidden
- // cursor modes, etc, and re-enable.
- //if (gFocusMgr.getMouseCapture())
- //{
- // gFocusMgr.setMouseCapture(NULL);
- // return TRUE;
- //}
- //}
- // let menus handle navigation keys
- if (gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
- {
- return TRUE;
- }
- // let menus handle navigation keys
- if (gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
- {
- return TRUE;
- }
- //some of context menus use this container, let context menu handle navigation keys
- if(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE))
- {
- return TRUE;
- }
- // Traverses up the hierarchy
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if( keyboard_focus )
- {
- LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
- // arrow keys move avatar while chatting hack
- if (chat_editor && chat_editor->hasFocus())
- {
- // If text field is empty, there's no point in trying to move
- // cursor with arrow keys, so allow movement
- if (chat_editor->getText().empty()
- || gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
- {
- // let Control-Up and Control-Down through for chat line history,
- if (!(key == KEY_UP && mask == MASK_CONTROL)
- && !(key == KEY_DOWN && mask == MASK_CONTROL))
- {
- switch(key)
- {
- case KEY_LEFT:
- case KEY_RIGHT:
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_HOME:
- // when chatbar is empty or ArrowKeysAlwaysMove set,
- // pass arrow keys on to avatar...
- return FALSE;
- default:
- break;
- }
- }
- }
- }
- if (keyboard_focus->handleKey(key, mask, FALSE))
- {
- return TRUE;
- }
- }
- if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
- {
- return TRUE;
- }
- // Try for a new-format gesture
- if (LLGestureManager::instance().triggerGesture(key, mask))
- {
- return TRUE;
- }
- // See if this is a gesture trigger. If so, eat the key and
- // don't pass it down to the menus.
- if (gGestureList.trigger(key, mask))
- {
- return TRUE;
- }
- // Topmost view gets a chance before the hierarchy
- // *FIX: get rid of this?
- //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- //if (top_ctrl)
- //{
- // if( top_ctrl->handleKey( key, mask, TRUE ) )
- // {
- // return TRUE;
- // }
- //}
- // give floaters first chance to handle TAB key
- // so frontmost floater gets focus
- if (key == KEY_TAB)
- {
- // if nothing has focus, go to first or last UI element as appropriate
- if (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL)
- {
- if (gMenuHolder) gMenuHolder->hideMenus();
- // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
- gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
- // do CTRL-TAB and CTRL-SHIFT-TAB logic
- if (mask & MASK_SHIFT)
- {
- mRootView->focusPrevRoot();
- }
- else
- {
- mRootView->focusNextRoot();
- }
- return TRUE;
- }
- }
-
- // give menus a chance to handle keys
- if (gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
- {
- return TRUE;
- }
-
- // give menus a chance to handle keys
- if (gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask))
- {
- return TRUE;
- }
- // don't pass keys on to world when something in ui has focus
- return gFocusMgr.childHasKeyboardFocus(mRootView)
- || LLMenuGL::getKeyboardMode()
- || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
- }
- BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
- {
- // HACK: We delay processing of return keys until they arrive as a Unicode char,
- // so that if you're typing chat text at low frame rate, we don't send the chat
- // until all keystrokes have been entered. JC
- // HACK: Numeric keypad <enter> on Mac is Unicode 3
- // HACK: Control-M on Windows is Unicode 13
- if ((uni_char == 13 && mask != MASK_CONTROL)
- || (uni_char == 3 && mask == MASK_NONE))
- {
- return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
- }
- // let menus handle navigation (jump) keys
- if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
- {
- return TRUE;
- }
- // Traverses up the hierarchy
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if( keyboard_focus )
- {
- if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
- {
- return TRUE;
- }
- //// Topmost view gets a chance before the hierarchy
- //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
- //{
- // return TRUE;
- //}
- return TRUE;
- }
- return FALSE;
- }
- void LLViewerWindow::handleScrollWheel(S32 clicks)
- {
- LLView::sMouseHandlerMessage.clear();
- LLUI::resetMouseIdleTimer();
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- mouse_captor->handleScrollWheel(local_x, local_y, clicks);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
- }
- return;
- }
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x;
- S32 local_y;
- top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
- }
- if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
- }
- return;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel not handled by view" << llendl;
- }
- // Zoom the camera in and out behavior
- if(top_ctrl == 0 && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY) )
- gAgent.handleScrollWheel(clicks);
- return;
- }
- void LLViewerWindow::moveCursorToCenter()
- {
- if (! gSavedSettings.getBOOL("DisableMouseWarp"))
- {
- S32 x = getWorldViewWidthScaled() / 2;
- S32 y = getWorldViewHeightScaled() / 2;
-
- //on a forced move, all deltas get zeroed out to prevent jumping
- mCurrentMousePoint.set(x,y);
- mLastMousePoint.set(x,y);
- mCurrentMouseDelta.set(0,0);
- LLUI::setMousePositionScreen(x, y);
- }
- }
- //////////////////////////////////////////////////////////////////////
- //
- // Hover handlers
- //
- void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
- {
- if (viewp)
- {
- if (!params.styled_message().empty())
- {
- params.styled_message.add().text("n---------n");
- }
- LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
- // NOTE: we skip "root" since it is assumed
- for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
- tooltip_it != end_tooltip_it;
- ++tooltip_it)
- {
- LLView* viewp = *tooltip_it;
-
- params.styled_message.add().text(viewp->getName());
- LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
- if (panelp && !panelp->getXMLFilename().empty())
- {
- params.styled_message.add()
- .text("(" + panelp->getXMLFilename() + ")")
- .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
- }
- params.styled_message.add().text("/");
- }
- }
- }
- // Update UI based on stored mouse position from mouse-move
- // event processing.
- void LLViewerWindow::updateUI()
- {
- static std::string last_handle_msg;
- LLConsole::updateClass();
- // animate layout stacks so we have up to date rect for world view
- LLLayoutStack::updateClass();
- updateWorldViewRect();
- LLView::sMouseHandlerMessage.clear();
- S32 x = mCurrentMousePoint.mX;
- S32 y = mCurrentMousePoint.mY;
- MASK mask = gKeyboard->currentMask(TRUE);
- if (gNoRender)
- {
- return;
- }
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
- {
- gDebugRaycastFaceHit = -1;
- gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
- &gDebugRaycastFaceHit,
- &gDebugRaycastIntersection,
- &gDebugRaycastTexCoord,
- &gDebugRaycastNormal,
- &gDebugRaycastBinormal);
- }
- updateMouseDelta();
- updateKeyboardFocus();
- BOOL handled = FALSE;
- BOOL handled_by_top_ctrl = FALSE;
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
- //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
- //build set of views containing mouse cursor by traversing UI hierarchy and testing
- //screen rect against mouse cursor
- view_handle_set_t mouse_hover_set;
- // constraint mouse enter events to children of mouse captor
- LLView* root_view = captor_view;
- // if mouse captor doesn't exist or isn't a LLView
- // then allow mouse enter events on entire UI hierarchy
- if (!root_view)
- {
- root_view = mRootView;
- }
- // include all ancestors of captor_view as automatically having mouse
- if (captor_view)
- {
- LLView* captor_parent_view = captor_view->getParent();
- while(captor_parent_view)
- {
- mouse_hover_set.insert(captor_parent_view->getHandle());
- captor_parent_view = captor_parent_view->getParent();
- }
- }
- // aggregate visible views that contain mouse cursor in display order
- // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
- if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
- it != top_ctrl->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- else
- {
- // walk UI tree in depth-first order
- for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
- it != root_view->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- // calculating the screen rect involves traversing the parent, so this is less than optimal
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
- if (viewp->getMouseOpaque())
- {
- // constrain further iteration to children of this widget
- it = viewp->beginTreeDFS();
- }
-
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- typedef std::vector<LLHandle<LLView> > view_handle_list_t;
- // call onMouseEnter() on all views which contain the mouse cursor but did not before
- view_handle_list_t mouse_enter_views;
- std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
- mMouseHoverViews.begin(), mMouseHoverViews.end(),
- std::back_inserter(mouse_enter_views));
- for (view_handle_list_t::iterator it = mouse_enter_views.begin();
- it != mouse_enter_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();