diff options
108 files changed, 9728 insertions, 5486 deletions
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp index 26802bbd1c..457c074ef1 100644 --- a/indra/llplugin/llpluginclassmedia.cpp +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -552,6 +552,23 @@ void LLPluginClassMedia::loadURI(const std::string &uri)  	sendMessage(message);  } +const char* LLPluginClassMedia::priorityToString(EPriority priority) +{ +	const char* result = "UNKNOWN"; +	switch(priority) +	{ +		case PRIORITY_UNLOADED:		result = "unloaded";	break; +		case PRIORITY_STOPPED:		result = "stopped";		break; +		case PRIORITY_HIDDEN:		result = "hidden";		break; +		case PRIORITY_SLIDESHOW:	result = "slideshow";	break; +		case PRIORITY_LOW:			result = "low";			break; +		case PRIORITY_NORMAL:		result = "normal";		break; +		case PRIORITY_HIGH:			result = "high";		break; +	} +	 +	return result; +} +  void LLPluginClassMedia::setPriority(EPriority priority)  {  	if(mPriority != priority) @@ -560,35 +577,28 @@ void LLPluginClassMedia::setPriority(EPriority priority)  		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); -		std::string priority_string; +		std::string priority_string = priorityToString(priority);  		switch(priority)  		{  			case PRIORITY_UNLOADED:	 -				priority_string = "unloaded";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_STOPPED:	 -				priority_string = "stopped";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_HIDDEN:	 -				priority_string = "hidden";	  				mSleepTime = 1.0f;  			break;  			case PRIORITY_SLIDESHOW: -				priority_string = "slideshow";		  				mSleepTime = 1.0f;  			break;  			case PRIORITY_LOW:		 -				priority_string = "low";		  				mSleepTime = 1.0f / 50.0f;  			break;  			case PRIORITY_NORMAL:	 -				priority_string = "normal";	  				mSleepTime = 1.0f / 100.0f;  			break;  			case PRIORITY_HIGH:		 -				priority_string = "high";		  				mSleepTime = 1.0f / 100.0f;  			break;  		} @@ -794,6 +804,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)  			{  				mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED;  			} +			else if(status == "done") +			{ +				mStatus = LLPluginClassMediaOwner::MEDIA_DONE; +			}  			else  			{  				// empty string or any unknown string diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h index 4f9763474e..90ecd1e073 100644 --- a/indra/llplugin/llpluginclassmedia.h +++ b/indra/llplugin/llpluginclassmedia.h @@ -150,6 +150,7 @@ public:  		PRIORITY_HIGH		// media has user focus and/or is taking up most of the screen  	}EPriority; +	static const char* priorityToString(EPriority priority);  	void setPriority(EPriority priority);  	void setLowPrioritySizeLimit(int size); diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h index 4690f09172..c798af29ca 100644 --- a/indra/llplugin/llpluginclassmediaowner.h +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -70,7 +70,8 @@ public:  		MEDIA_ERROR,		// navigation/preroll failed  		MEDIA_PLAYING,		// playing (only for time-based media)  		MEDIA_PAUSED,		// paused (only for time-based media) -		 +		MEDIA_DONE			// finished playing (only for time-based media) +	  	} EMediaStatus;  	virtual ~LLPluginClassMediaOwner() {}; diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp index e053477d58..75905d0927 100644 --- a/indra/llui/lllineeditor.cpp +++ b/indra/llui/lllineeditor.cpp @@ -1544,18 +1544,24 @@ void LLLineEditor::drawBackground()  		image = mBgImage;  	} +	F32 alpha = getDrawContext().mAlpha;  	// optionally draw programmatic border  	if (has_focus)  	{ +		LLColor4 tmp_color = gFocusMgr.getFocusColor(); +		tmp_color.setAlpha(alpha);  		image->drawBorder(0, 0, getRect().getWidth(), getRect().getHeight(), -						  gFocusMgr.getFocusColor(), +						  tmp_color,  						  gFocusMgr.getFocusFlashWidth());  	} -	image->draw(getLocalRect()); +	LLColor4 tmp_color = UI_VERTEX_COLOR; +	tmp_color.setAlpha(alpha); +	image->draw(getLocalRect(), tmp_color);  }  void LLLineEditor::draw()  { +	F32 alpha = getDrawContext().mAlpha;  	S32 text_len = mText.length();  	static LLUICachedControl<S32> lineeditor_cursor_thickness ("UILineEditorCursorThickness", 0);  	static LLUICachedControl<S32> lineeditor_v_pad ("UILineEditorVPad", 0); @@ -1608,8 +1614,10 @@ void LLLineEditor::draw()  	{  		text_color = mReadOnlyFgColor.get();  	} +	text_color.setAlpha(alpha);  	LLColor4 label_color = mTentativeFgColor.get(); - +	label_color.setAlpha(alpha); +	  	if (hasPreeditString())  	{  		// Draw preedit markers.  This needs to be before drawing letters. @@ -1632,7 +1640,7 @@ void LLLineEditor::draw()  						preedit_pixels_right - preedit_standout_gap - 1,  						background.mBottom + preedit_standout_position - preedit_standout_thickness,  						(text_color * preedit_standout_brightness  -						 + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(1.0f)); +						 + mPreeditBgColor * (1 - preedit_standout_brightness)).setAlpha(alpha/*1.0f*/));  				}  				else  				{ @@ -1641,7 +1649,7 @@ void LLLineEditor::draw()  						preedit_pixels_right - preedit_marker_gap - 1,  						background.mBottom + preedit_marker_position - preedit_marker_thickness,  						(text_color * preedit_marker_brightness -						 + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(1.0f)); +						 + mPreeditBgColor * (1 - preedit_marker_brightness)).setAlpha(alpha/*1.0f*/));  				}  			}  		} @@ -1684,15 +1692,17 @@ void LLLineEditor::draw()  		if( (rendered_pixels_right < (F32)mMaxHPixels) && (rendered_text < text_len) )  		{  			LLColor4 color = mHighlightColor; +			color.setAlpha(alpha);  			// selected middle  			S32 width = mGLFont->getWidth(mText.getWString().c_str(), mScrollHPos + rendered_text, select_right - mScrollHPos - rendered_text);  			width = llmin(width, mMaxHPixels - llround(rendered_pixels_right));  			gl_rect_2d(llround(rendered_pixels_right), cursor_top, llround(rendered_pixels_right)+width, cursor_bottom, color); +			LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );  			rendered_text += mGLFont->render(   				mText, mScrollHPos + rendered_text,  				rendered_pixels_right, text_bottom, -				LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ), +				tmp_color,  				LLFontGL::LEFT, LLFontGL::BOTTOM,  				0,  				LLFontGL::NO_SHADOW, @@ -1758,8 +1768,9 @@ void LLLineEditor::draw()  					cursor_right, cursor_bottom, text_color);  				if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())  				{ +					LLColor4 tmp_color( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], alpha );  					mGLFont->render(mText, getCursor(), (F32)(cursor_left + lineeditor_cursor_thickness / 2), text_bottom,  -						LLColor4( 1.f - text_color.mV[0], 1.f - text_color.mV[1], 1.f - text_color.mV[2], 1 ), +						tmp_color,  						LLFontGL::LEFT, LLFontGL::BOTTOM,  						0,  						LLFontGL::NO_SHADOW, diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 732c01614b..cde4c75518 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -44,6 +44,7 @@  #include "lluictrlfactory.h"  #include "llrender.h"  #include "llfloater.h" +#include "lltrans.h"  //---------------------------------------------------------------------------- @@ -153,6 +154,8 @@ LLTabContainer::LLTabContainer(const LLTabContainer::Params& p)  	mRightTabBtnOffset(p.tab_padding_right),  	mTotalTabWidth(0),  	mTabPosition(p.tab_position), +	mFontHalign(p.font_halign), +	mFont(p.font.isProvided() ? p.font() : (mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall())),  	mFirstTabParams(p.first_tab),  	mMiddleTabParams(p.middle_tab),  	mLastTabParams(p.last_tab) @@ -401,12 +404,6 @@ void LLTabContainer::draw()  					}  				}  			} -			LLUI::pushMatrix(); -			{ -				LLUI::translate((F32)tuple->mButton->getRect().mLeft, (F32)tuple->mButton->getRect().mBottom, 0.f); -				tuple->mButton->draw(); -			} -			LLUI::popMatrix();  			idx++;  		} @@ -641,12 +638,6 @@ BOOL LLTabContainer::handleToolTip( S32 x, S32 y, MASK mask)  				}  			}  		} - -		for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) -		{ -			LLTabTuple* tuple = *iter; -			tuple->mButton->setVisible( FALSE ); -		}  	}  	return handled;  } @@ -836,8 +827,6 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		// already a child of mine  		return;  	} -	const LLFontGL* font = -		(mIsVertical ? LLFontGL::getFontSansSerif() : LLFontGL::getFontSansSerifSmall());  	// Store the original label for possible xml export.  	child->setLabel(label); @@ -847,7 +836,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  	S32 button_width = mMinTabWidth;  	if (!mIsVertical)  	{ -		button_width = llclamp(font->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth); +		button_width = llclamp(mFont->getWidth(trimmed_label) + tab_padding, mMinTabWidth, mMaxTabWidth);  	}  	// Tab panel @@ -934,7 +923,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		params.name(trimmed_label);  		params.rect(btn_rect);  		params.initial_value(trimmed_label); -		params.font(font); +		params.font(mFont);  		textbox = LLUICtrlFactory::create<LLTextBox> (params);  		LLButton::Params p; @@ -950,12 +939,12 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  			p.rect(btn_rect);  			p.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT);  			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(font); +			p.font(mFont);  			p.label(trimmed_label);  			p.image_unselected(mMiddleTabParams.tab_left_image_unselected);  			p.image_selected(mMiddleTabParams.tab_left_image_selected);  			p.scale_image(true); -			p.font_halign = LLFontGL::LEFT; +			p.font_halign = mFontHalign;  			p.tab_stop(false);  			if (indent)  			{ @@ -965,18 +954,13 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  		}  		else  		{ -			std::string tooltip = trimmed_label; -			tooltip += "\nAlt-Left arrow for previous tab"; -			tooltip += "\nAlt-Right arrow for next tab"; -  			LLButton::Params p;  			p.name(std::string(child->getName()) + " tab");  			p.rect(btn_rect);  			p.click_callback.function(boost::bind(&LLTabContainer::onTabBtn, this, _2, child)); -			p.font(font); +			p.font(mFont);  			p.label(trimmed_label);  			p.visible(false); -			p.tool_tip(tooltip);  			p.scale_image(true);  			p.image_unselected(tab_img);  			p.image_selected(tab_selected_img); @@ -984,7 +968,7 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel)  			// Try to squeeze in a bit more text  			p.pad_left(4);  			p.pad_right(2); -			p.font_halign = LLFontGL::LEFT; +			p.font_halign = mFontHalign;  			p.follows.flags = FOLLOWS_LEFT;  			p.follows.flags = FOLLOWS_LEFT; @@ -1505,7 +1489,6 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L  		if (!mIsVertical)  		{ -			const LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();  			// remove current width from total tab strip width  			mTotalTabWidth -= tuple->mButton->getRect().getWidth(); @@ -1516,7 +1499,7 @@ void LLTabContainer::setTabImage(LLPanel* child, std::string image_name, const L  			tuple->mPadding = image_overlay_width;  			tuple->mButton->setRightHPad(6); -			tuple->mButton->reshape(llclamp(fontp->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),  +			tuple->mButton->reshape(llclamp(mFont->getWidth(tuple->mButton->getLabelSelected()) + tab_padding + tuple->mPadding, mMinTabWidth, mMaxTabWidth),   									tuple->mButton->getRect().getHeight());  			// add back in button width to total tab strip width  			mTotalTabWidth += tuple->mButton->getRect().getWidth(); diff --git a/indra/llui/lltabcontainer.h b/indra/llui/lltabcontainer.h index a81974cd42..be9c6c7d06 100644 --- a/indra/llui/lltabcontainer.h +++ b/indra/llui/lltabcontainer.h @@ -262,6 +262,9 @@ private:  	S32								mTabHeight;  	LLFrameTimer					mDragAndDropDelayTimer; +	 +	LLFontGL::HAlign                mFontHalign; +	const LLFontGL*					mFont;  	TabParams						mFirstTabParams;  	TabParams						mMiddleTabParams; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0add3fb500..2b1d677ffb 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -419,9 +419,6 @@ void LLTextBase::drawCursor()  			return;  		} -		if (!mTextRect.contains(cursor_rect)) -			return; -  		// Draw the cursor  		// (Flash the cursor every half second starting a fixed time after the last keystroke)  		F32 elapsed = mCursorBlinkTimer.getElapsedTimeF32(); @@ -973,7 +970,7 @@ void LLTextBase::draw()  							: hasFocus()   								? mFocusBgColor.get()   								: mWriteableBgColor.get(); -		gl_rect_2d(mDocumentView->getRect(), bg_color, TRUE); +		gl_rect_2d(mTextRect, bg_color, TRUE);  	}  	// draw document view @@ -1034,13 +1031,13 @@ S32 LLTextBase::getLeftOffset(S32 width)  	switch (mHAlign)  	{  	case LLFontGL::LEFT: -		return 0; +		return mHPad;  	case LLFontGL::HCENTER: -		return (mTextRect.getWidth() - width) / 2; +		return mHPad + (mTextRect.getWidth() - width - mHPad) / 2;  	case LLFontGL::RIGHT:  		return mTextRect.getWidth() - width;  	default: -		return 0; +		return mHPad;  	}  } @@ -1048,8 +1045,6 @@ S32 LLTextBase::getLeftOffset(S32 width)  static LLFastTimer::DeclareTimer FTM_TEXT_REFLOW ("Text Reflow");  void LLTextBase::reflow(S32 start_index)  { -	if (!mReflowNeeded) return; -  	LLFastTimer ft(FTM_TEXT_REFLOW);  	updateSegments(); @@ -1078,7 +1073,7 @@ void LLTextBase::reflow(S32 start_index)  		segment_set_t::iterator seg_iter = mSegments.begin();  		S32 seg_offset = 0;  		S32 line_start_index = 0; -		const S32 text_width = mTextRect.getWidth();  // optionally reserve room for margin +		const S32 text_width = mTextRect.getWidth() - mHPad;  // reserve room for margin  		S32 remaining_pixels = text_width;  		LLWString text(getWText());  		S32 line_count = 0; @@ -2037,7 +2032,6 @@ void LLTextBase::updateRects()  	}  	else  	{ -  		mContentsRect = mLineInfoList.begin()->mRect;  		for (line_list_t::const_iterator line_iter = ++mLineInfoList.begin();  			line_iter != mLineInfoList.end(); @@ -2046,13 +2040,28 @@ void LLTextBase::updateRects()  			mContentsRect.unionWith(line_iter->mRect);  		} -		mContentsRect.mRight += mHPad; +		mContentsRect.mLeft = 0;  		mContentsRect.mTop += mVPad; -		// get around rounding errors when clipping text against rectangle -		mContentsRect.stretch(1); + +		S32 delta_pos = -mContentsRect.mBottom; +		// move line segments to fit new document rect +		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) +		{ +			it->mRect.translate(0, delta_pos); +		} +		mContentsRect.translate(0, delta_pos);  	} +	// update document container dimensions according to text contents +	LLRect doc_rect = mContentsRect; +	// use old mTextRect constraint document to width of viewable region +	doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); + +	mDocumentView->setShape(doc_rect); +	//update mTextRect *after* mDocumentView has been resized +	// so that scrollbars are added if document needs to scroll +	// since mTextRect does not include scrollbars  	LLRect old_text_rect = mTextRect;  	mTextRect = mScroller ? mScroller->getContentWindowRect() : getLocalRect();  	//FIXME: replace border with image? @@ -2060,43 +2069,14 @@ void LLTextBase::updateRects()  	{  		mTextRect.stretch(-1);  	} -	mTextRect.mLeft += mHPad; -	mTextRect.mTop -= mVPad;  	if (mTextRect != old_text_rect)  	{  		needsReflow();  	} -	// change document rect size too -	LLRect document_rect; -	if (mScroller) -	{ -		// document is size of scroller or size of text contents, whichever is larger -		document_rect.setOriginAndSize(0, 0,  -									mScroller->getContentWindowRect().getWidth(),  -									llmax(mScroller->getContentWindowRect().getHeight(), mContentsRect.getHeight())); -	} -	else -	{ -		// document size is just extents of reflowed text, reset to origin 0,0 -		document_rect.set(0,  -						getLocalRect().getHeight(),  -						getLocalRect().getWidth(),  -						llmin(0, getLocalRect().getHeight() - mContentsRect.getHeight())); -	} -	mDocumentView->setShape(document_rect); - -	// after making document big enough to hold all the text, move the text to fit in the document -	if (!mLineInfoList.empty()) -	{ -		S32 delta_pos = mDocumentView->getRect().getHeight() - mLineInfoList.begin()->mRect.mTop - mVPad; -		// move line segments to fit new document rect -		for (line_list_t::iterator it = mLineInfoList.begin(); it != mLineInfoList.end(); ++it) -		{ -			it->mRect.translate(0, delta_pos); -		} -		mContentsRect.translate(0, delta_pos); -	} +	// update document container again, using new mTextRect +	doc_rect.mRight = doc_rect.mLeft + mTextRect.getWidth(); +	mDocumentView->setShape(doc_rect);  } @@ -2398,7 +2378,6 @@ S32	LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  	{  		if (text[last_char] == '\n')   		{ -			last_char++;  			break;  		}  	} @@ -2418,9 +2397,14 @@ S32	LLNormalTextSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  		// If at the beginning of a line, and a single character won't fit, draw it anyway  		num_chars = 1;  	} -	if (mStart + segment_offset + num_chars == mEditor.getLength()) + +	// include *either* the EOF or newline character in this run of text +	// but not both +	S32 last_char_in_run = mStart + segment_offset + num_chars; +	// check length first to avoid indexing off end of string +	if (last_char_in_run >= mEditor.getLength()  +		|| text[last_char_in_run] == '\n')  	{ -		// include terminating NULL  		num_chars++;  	}  	return num_chars; @@ -2442,12 +2426,14 @@ void LLNormalTextSegment::dump() const  // LLInlineViewSegment  // -LLInlineViewSegment::LLInlineViewSegment(LLView* view, S32 start, S32 end, bool force_new_line, S32 hpad, S32 vpad) +LLInlineViewSegment::LLInlineViewSegment(const Params& p, S32 start, S32 end)  :	LLTextSegment(start, end), -	mView(view), -	mForceNewLine(force_new_line), -	mHPad(hpad), // one sided padding (applied to left and right) -	mVPad(vpad) +	mView(p.view), +	mForceNewLine(p.force_newline), +	mLeftPad(p.left_pad), +	mRightPad(p.right_pad), +	mTopPad(p.top_pad), +	mBottomPad(p.bottom_pad)  {  }  @@ -2467,8 +2453,8 @@ void	LLInlineViewSegment::getDimensions(S32 first_char, S32 num_chars, S32& widt  	}  	else  	{ -		width = mHPad * 2 + mView->getRect().getWidth(); -		height = mVPad * 2 + mView->getRect().getHeight(); +		width = mLeftPad + mRightPad + mView->getRect().getWidth(); +		height = mBottomPad + mTopPad + mView->getRect().getHeight();  	}  } @@ -2491,14 +2477,14 @@ S32	LLInlineViewSegment::getNumChars(S32 num_pixels, S32 segment_offset, S32 lin  void LLInlineViewSegment::updateLayout(const LLTextBase& editor)  {  	LLRect start_rect = editor.getDocRectFromDocIndex(mStart); -	mView->setOrigin(start_rect.mLeft + mHPad, start_rect.mBottom + mVPad); +	mView->setOrigin(start_rect.mLeft + mLeftPad, start_rect.mBottom + mBottomPad);  }  F32	LLInlineViewSegment::draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)  {  	// return padded width of widget  	// widget is actually drawn during mDocumentView's draw() -	return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mHPad * 2); +	return (F32)(draw_rect.mLeft + mView->getRect().getWidth() + mLeftPad + mRightPad);  }  void LLInlineViewSegment::unlinkFromDocument(LLTextBase* editor) diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index d0787f001e..14fd786127 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -459,7 +459,17 @@ public:  class LLInlineViewSegment : public LLTextSegment  {  public: -	LLInlineViewSegment(LLView* widget, S32 start, S32 end, bool force_new_line, S32 hpad = 0, S32 vpad = 0); +	struct Params : public LLInitParam::Block<Params> +	{ +		Mandatory<LLView*>		view; +		Optional<bool>			force_newline; +		Optional<S32>			left_pad, +								right_pad, +								bottom_pad, +								top_pad; +	}; + +	LLInlineViewSegment(const Params& p, S32 start, S32 end);  	~LLInlineViewSegment();  	/*virtual*/ void		getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const;  	/*virtual*/ S32			getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const; @@ -470,8 +480,10 @@ public:  	/*virtual*/ void		linkToDocument(class LLTextBase* editor);  private: -	S32 mHPad; -	S32 mVPad; +	S32 mLeftPad; +	S32 mRightPad; +	S32 mTopPad; +	S32 mBottomPad;  	LLView* mView;  	bool	mForceNewLine;  }; diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 570ca4b998..f0238dba49 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -2307,7 +2307,7 @@ void LLTextEditor::insertText(const std::string &new_text)  	setEnabled( enabled );  } -void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_new_line, S32 hpad, S32 vpad) +void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)  {  	// Save old state  	S32 selection_start = mSelectionStart; @@ -2321,12 +2321,9 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,  	setCursorPos(old_length); -	LLWString widget_wide_text; +	LLWString widget_wide_text = utf8str_to_wstring(text); -	// Add carriage return if not first line -	widget_wide_text = utf8str_to_wstring(widget_text); - -	LLTextSegmentPtr segment = new LLInlineViewSegment(widget, old_length, old_length + widget_text.size(), force_new_line, hpad, vpad); +	LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size());  	insert(getLength(), widget_wide_text, FALSE, segment);  	needsReflow(); @@ -2349,7 +2346,7 @@ void LLTextEditor::appendWidget(LLView* widget, const std::string &widget_text,  		setCursorPos(cursor_pos);  	} -	if( !allow_undo ) +	if (!allow_undo)  	{  		blockUndo();  	} diff --git a/indra/llui/lltexteditor.h b/indra/llui/lltexteditor.h index 4847f4d117..10fc94dedc 100644 --- a/indra/llui/lltexteditor.h +++ b/indra/llui/lltexteditor.h @@ -166,7 +166,7 @@ public:  	// inserts text at cursor  	void			insertText(const std::string &text); -	void			appendWidget(LLView* widget, const std::string &widget_text, bool allow_undo, bool force_newline, S32 hpad, S32 vpad); +	void			appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo);  	// Non-undoable  	void			setText(const LLStringExplicit &utf8str); diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp new file mode 100644 index 0000000000..0daff85395 --- /dev/null +++ b/indra/llwindow/lldragdropwin32.cpp @@ -0,0 +1,295 @@ +/**
 + * @file lldragdrop32.cpp
 + * @brief Handler for Windows specific drag and drop (OS to client) code
 + *
 + * $LicenseInfo:firstyear=2001&license=viewergpl$
 + *
 + * Copyright (c) 2001-2009, 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$
 + */
 +
 +#if LL_WINDOWS
 +
 +#include "linden_common.h"
 +
 +#define WIN32_LEAN_AND_MEAN
 +#include <windows.h>
 +
 +#include "llwindowwin32.h"
 +#include "llkeyboardwin32.h"
 +#include "lldragdropwin32.h"
 +
 +#include "llwindowcallbacks.h"
 +
 +#include <windows.h>
 +#include <ole2.h>
 +#include <shlobj.h>
 +#include <shellapi.h>
 +#include <shlwapi.h>
 +
 +// FIXME: this should be done in CMake
 +#pragma comment( lib, "shlwapi.lib" )
 +
 +class LLDragDropWin32Target: 
 +	public IDropTarget
 +{
 +	public:
 +		LLDragDropWin32Target( HWND  hWnd ) :
 +		  mWindowHandle( hWnd ),
 +		  mRefCount( 0 )
 +		{
 +			strcpy(szFileDropped,"");
 +			bDropTargetValid = false;
 +			bTextDropped = false;		
 +		};
 +
 +		/* IUnknown methods */
 +		STDMETHOD_( ULONG, AddRef )( void )
 +		{
 +			return ++mRefCount;
 +		};
 +
 +		STDMETHOD_( ULONG, Release )( void )
 +		{
 +			if ( --mRefCount == 0 )
 +			{
 +				delete this;
 +				return 0;
 +			}
 +			return mRefCount;
 +		};
 +
 +		STDMETHOD ( QueryInterface )( REFIID iid, void ** ppvObject )
 +		{
 +			if ( iid == IID_IUnknown || iid == IID_IDropTarget )
 +			{
 +				*ppvObject = this;
 +				AddRef();
 +				return S_OK;
 +			};
 +
 +			*ppvObject = NULL;
 +			return E_NOINTERFACE;
 +		};
 +		
 +		/* IDropTarget methods */
 +		STDMETHOD (DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
 +		{
 +			HRESULT hr = E_INVALIDARG;
 +			bDropTargetValid = false;
 +			bTextDropped = false;
 +			*pdwEffect=DROPEFFECT_NONE;
 +			
 +			FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
 +			STGMEDIUM medium;
 +				
 +			if (pDataObj && SUCCEEDED (pDataObj->GetData (&fmte, &medium)))
 +			{
 +				// We can Handle Only one File At a time !!!
 +				if (1 == DragQueryFile ((HDROP)medium.hGlobal,0xFFFFFFFF,NULL,0 ))
 +				{
 +					// Get the File Name
 +					if (DragQueryFileA((HDROP)medium.hGlobal, 0, szFileDropped,MAX_PATH))
 +					{
 +						if (!PathIsDirectoryA(szFileDropped))
 +						{
 +							char szTempFile[MAX_PATH];
 +							_splitpath(szFileDropped,NULL,NULL,NULL,szTempFile);
 +
 +//							if (!stricmp(szTempFile,".lnk"))
 +//							{
 +//								if (ResolveLink(szFileDropped,szTempFile))
 +//								{
 +//									strcpy(szFileDropped,szTempFile);
 +//									*pdwEffect=DROPEFFECT_COPY;
 +//									We Want to Create a Copy
 +//									bDropTargetValid = true;
 +//									hr = S_OK;
 +//								}
 +//							}
 +//							else
 +//							{
 +								*pdwEffect=DROPEFFECT_COPY;
 +								//We Want to Create a Copy
 +								bDropTargetValid = true;
 +								hr = S_OK;
 +//							}
 +						}
 +					}
 +				}
 +
 +				if (medium.pUnkForRelease)
 +					medium.pUnkForRelease->Release ();
 +				else
 +					GlobalFree (medium.hGlobal);
 +			}
 +			else 
 +			{
 +				fmte.cfFormat = CF_TEXT;
 +				fmte.ptd = NULL;
 +				fmte.dwAspect = DVASPECT_CONTENT;
 +				fmte.lindex = -1;
 +				fmte.tymed = TYMED_HGLOBAL; 
 +
 +				// Does the drag source provide CF_TEXT ?    
 +				if (NOERROR == pDataObj->QueryGetData(&fmte))
 +				{
 +					bDropTargetValid = true;
 +					bTextDropped = true;
 +					*pdwEffect=DROPEFFECT_COPY;
 +					hr = S_OK;
 +				}
 +			}
 +				return hr;
 +
 +
 +
 +		};
 +
 +		STDMETHOD (DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
 +		{
 +			HRESULT hr = S_OK;
 +			if (bDropTargetValid) 
 +				*pdwEffect=DROPEFFECT_COPY;
 +
 +			return hr;
 +		};
 +
 +		STDMETHOD (DragLeave)(void)
 +		{
 +			HRESULT hr = S_OK;
 +			strcpy(szFileDropped,"");
 +			return hr;
 +		};
 +
 +		STDMETHOD (Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
 +		{
 +			HRESULT hr = S_OK;
 +			if (bDropTargetValid) 
 +			{
 +				*pdwEffect=DROPEFFECT_COPY;
 +			
 +				FORMATETC fmte;
 +				STGMEDIUM medium;
 +
 +				if (bTextDropped)
 +				{
 +					fmte.cfFormat = CF_TEXT;
 +					fmte.ptd = NULL;
 +					fmte.dwAspect = DVASPECT_CONTENT;  
 +					fmte.lindex = -1;
 +					fmte.tymed = TYMED_HGLOBAL;       
 +
 +					hr = pDataObj->GetData(&fmte, &medium);
 +					HGLOBAL hText = medium.hGlobal;
 +					LPSTR lpszText = (LPSTR)GlobalLock(hText);
 +
 +					LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(mWindowHandle, GWL_USERDATA);
 +					if (NULL != window_imp)
 +					{
 +						LLCoordGL gl_coord( pt.x, pt.y);
 +						LLCoordWindow cursor_coord_window( pt.x, pt.y );
 +						window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +						llinfos << "### (Drop) URL is: " << lpszText << llendl;
 +						llinfos << "###        raw coords are: " << pt.x << " x " << pt.y << llendl;
 +						llinfos << "###         GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << llendl;
 +						llinfos << llendl;
 +
 +						MASK mask = gKeyboard->currentMask(TRUE);
 +						window_imp->completeDropRequest( gl_coord, mask, std::string( lpszText ) );
 +					};
 +
 +					GlobalUnlock(hText);
 +					ReleaseStgMedium(&medium);
 +				}
 +			}
 +			return hr;
 +		};
 +	   
 +	private:
 +		ULONG mRefCount;
 +		HWND mWindowHandle;
 +		char szFileDropped[1024];
 +		bool bDropTargetValid;
 +		bool bTextDropped;
 +		friend class LLWindowWin32;
 +};
 +
 +LLDragDropWin32::LLDragDropWin32() :
 +	mDropTarget( NULL ),
 +	mDropWindowHandle( NULL )
 +
 +{
 +}
 +
 +LLDragDropWin32::~LLDragDropWin32()
 +{
 +}
 +
 +bool LLDragDropWin32::init( HWND hWnd )
 +{
 +	if (NOERROR != OleInitialize(NULL))
 +		return FALSE; 
 +
 +	mDropTarget = new LLDragDropWin32Target( hWnd );
 +	if ( mDropTarget )
 +	{
 +		HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, TRUE );
 +		if ( S_OK == result )
 +		{
 +			result = RegisterDragDrop( hWnd, mDropTarget );
 +			if ( S_OK != result )
 +			{
 +				// RegisterDragDrop failed
 +				return false;
 +			};
 +
 +			// all ok
 +			mDropWindowHandle = hWnd;
 +		}
 +		else
 +		{
 +			// Unable to lock OLE object
 +			return false;
 +		};
 +	};
 +
 +	// success
 +	return true;
 +}
 +
 +void LLDragDropWin32::reset()
 +{
 +	if ( mDropTarget )
 +	{
 +		CoLockObjectExternal( mDropTarget, FALSE, TRUE );
 +		RevokeDragDrop( mDropWindowHandle );
 +		mDropTarget->Release();  
 +	};
 +	
 +	OleUninitialize();
 +}
 +
 +#endif
 diff --git a/indra/llwindow/lldragdropwin32.h b/indra/llwindow/lldragdropwin32.h new file mode 100644 index 0000000000..6137e5eb65 --- /dev/null +++ b/indra/llwindow/lldragdropwin32.h @@ -0,0 +1,55 @@ +/**
 + * @file lldragdrop32.cpp
 + * @brief Handler for Windows specific drag and drop (OS to client) code
 + *
 + * $LicenseInfo:firstyear=2004&license=viewergpl$
 + *
 + * Copyright (c) 2004-2009, 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$
 + */
 +
 +#ifndef LL_LLDRAGDROP32_H
 +#define LL_LLDRAGDROP32_H
 +
 +#include <windows.h>
 +#include <ole2.h>
 +#include <shlobj.h>
 +#include <shlwapi.h>
 +
 +class LLDragDropWin32
 +{
 +	public:
 +		LLDragDropWin32();
 +		~LLDragDropWin32();
 +
 +		bool init( HWND hWnd );
 +		void reset();
 +
 +	private:
 +		IDropTarget* mDropTarget;
 +		HWND mDropWindowHandle;
 +};
 +
 +#endif
 diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 72f9997149..1098529e1c 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -163,6 +163,11 @@ void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *da  {  } +BOOL LLWindowCallbacks::handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data ) +{ +	return FALSE; +} +  BOOL LLWindowCallbacks::handleTimerEvent(LLWindow *window)  {  	return FALSE; diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index abc66c42a2..3a09100168 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -68,6 +68,7 @@ public:  	virtual void handleWindowBlock(LLWindow *window);							// window is taking over CPU for a while  	virtual void handleWindowUnblock(LLWindow *window);							// window coming back after taking over CPU for a while  	virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); +	virtual BOOL handleDrop(LLWindow *window, LLCoordGL pos, MASK mask, std::string data);  	virtual BOOL handleTimerEvent(LLWindow *window);  	virtual BOOL handleDeviceChange(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c608c21d05..da096b9a0a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1,3647 +1,3728 @@ -/**  - * @file llwindowwin32.cpp - * @brief Platform-dependent implementation of llwindow - * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - *  - * Copyright (c) 2001-2009, 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 "linden_common.h" - -#if LL_WINDOWS && !LL_MESA_HEADLESS - -#include "llwindowwin32.h" - -// LLWindow library includes -#include "llkeyboardwin32.h" -#include "llpreeditor.h" -#include "llwindowcallbacks.h" - -// Linden library includes -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" - -// System includes -#include <commdlg.h> -#include <WinUser.h> -#include <mapi.h> -#include <process.h>	// for _spawn -#include <shellapi.h> -#include <Imm.h> - -// Require DirectInput version 8 -#define DIRECTINPUT_VERSION 0x0800 - -#include <dinput.h> -#include <Dbt.h.> - -#include "llmemtype.h" -// culled from winuser.h -#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */ -const S32	WM_MOUSEWHEEL = 0x020A; -#endif -#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */ -const S32	WHEEL_DELTA = 120;     /* Value for rolling one detent */ -#endif -const S32	MAX_MESSAGE_PER_UPDATE = 20; -const S32	BITS_PER_PIXEL = 32; -const S32	MAX_NUM_RESOLUTIONS = 32; -const F32	ICON_FLASH_TIME = 0.5f; - -extern BOOL gDebugWindowProc; - -LPWSTR gIconResource = IDI_APPLICATION; - -LLW32MsgCallback gAsyncMsgCallback = NULL; - -// -// LLWindowWin32 -// - -void show_window_creation_error(const std::string& title) -{ -	LL_WARNS("Window") << title << LL_ENDL; -} - -//static -BOOL LLWindowWin32::sIsClassRegistered = FALSE; - -BOOL	LLWindowWin32::sLanguageTextInputAllowed = TRUE; -BOOL	LLWindowWin32::sWinIMEOpened = FALSE; -HKL		LLWindowWin32::sWinInputLocale = 0; -DWORD	LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; -DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; -LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); - -// The following class LLWinImm delegates Windows IMM APIs. -// We need this because some language versions of Windows, -// e.g., US version of Windows XP, doesn't install IMM32.DLL -// as a default, and we can't link against imm32.lib statically. -// I believe DLL loading of this type is best suited to do -// in a static initialization of a class.  What I'm not sure is -// whether it follows the Linden Conding Standard...  -// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members - -class LLWinImm -{ -public: -	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; } - -public: -	// Wrappers for IMM API. -	static BOOL		isIME(HKL hkl);															 -	static HWND		getDefaultIMEWnd(HWND hwnd); -	static HIMC		getContext(HWND hwnd);													 -	static BOOL		releaseContext(HWND hwnd, HIMC himc); -	static BOOL		getOpenStatus(HIMC himc);												 -	static BOOL		setOpenStatus(HIMC himc, BOOL status);									 -	static BOOL		getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence);	 -	static BOOL		setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);		 -	static BOOL		getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					 -	static BOOL		setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					 -	static LONG		getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); -	static BOOL		setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); -	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont); -	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); -	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); - -private: -	LLWinImm(); -	~LLWinImm(); - -private: -	// Pointers to IMM API. -	BOOL	 	(WINAPI *mImmIsIME)(HKL); -	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND); -	HIMC		(WINAPI *mImmGetContext)(HWND); -	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC); -	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC); -	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL); -	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); -	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); -	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); -	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); -	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); -	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); -	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); -	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); -	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); - -private: -	HMODULE		mHImmDll; -	static LLWinImm sTheInstance; -}; - -LLWinImm LLWinImm::sTheInstance; - -LLWinImm::LLWinImm() : mHImmDll(NULL) -{ -	// Check system metrics  -	if ( !GetSystemMetrics( SM_DBCSENABLED ) ) -		return; -	 - -	mHImmDll = LoadLibraryA("Imm32"); -	if (mHImmDll != NULL) -	{ -		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME"); -		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); -		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext"); -		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext"); -		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus"); -		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus"); -		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); -		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus"); -		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); -		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); -		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); -		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); -		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); -		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); -		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME"); - -		if (mImmIsIME == NULL || -			mImmGetDefaultIMEWnd == NULL || -			mImmGetContext == NULL || -			mImmReleaseContext == NULL || -			mImmGetOpenStatus == NULL || -			mImmSetOpenStatus == NULL || -			mImmGetConversionStatus == NULL || -			mImmSetConversionStatus == NULL || -			mImmGetCompostitionWindow == NULL || -			mImmSetCompostitionWindow == NULL || -			mImmGetCompositionString == NULL || -			mImmSetCompositionString == NULL || -			mImmSetCompositionFont == NULL || -			mImmSetCandidateWindow == NULL || -			mImmNotifyIME == NULL) -		{ -			// If any of the above API entires are not found, we can't use IMM API.   -			// So, turn off the IMM support.  We should log some warning message in  -			// the case, since it is very unusual; these APIs are available from  -			// the beginning, and all versions of IMM32.DLL should have them all.   -			// Unfortunately, this code may be executed before initialization of  -			// the logging channel (llwarns), and we can't do it here...  Yes, this  -			// is one of disadvantages to use static constraction to DLL loading.  -			FreeLibrary(mHImmDll); -			mHImmDll = NULL; - -			// If we unload the library, make sure all the function pointers are cleared -			mImmIsIME = NULL; -			mImmGetDefaultIMEWnd = NULL; -			mImmGetContext = NULL; -			mImmReleaseContext = NULL; -			mImmGetOpenStatus = NULL; -			mImmSetOpenStatus = NULL; -			mImmGetConversionStatus = NULL; -			mImmSetConversionStatus = NULL; -			mImmGetCompostitionWindow = NULL; -			mImmSetCompostitionWindow = NULL; -			mImmGetCompositionString = NULL; -			mImmSetCompositionString = NULL; -			mImmSetCompositionFont = NULL; -			mImmSetCandidateWindow = NULL; -			mImmNotifyIME = NULL; -		} -	} -} - - -// static  -BOOL	LLWinImm::isIME(HKL hkl)															 -{  -	if ( sTheInstance.mImmIsIME ) -		return sTheInstance.mImmIsIME(hkl);  -	return FALSE; -} - -// static  -HIMC		LLWinImm::getContext(HWND hwnd) -{ -	if ( sTheInstance.mImmGetContext ) -		return sTheInstance.mImmGetContext(hwnd);  -	return 0; -} - -//static  -BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc) -{  -	if ( sTheInstance.mImmIsIME ) -		return sTheInstance.mImmReleaseContext(hwnd, himc);  -	return FALSE; -} - -// static  -BOOL		LLWinImm::getOpenStatus(HIMC himc) -{  -	if ( sTheInstance.mImmGetOpenStatus ) -		return sTheInstance.mImmGetOpenStatus(himc);  -	return FALSE; -} - -// static  -BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)									 -{  -	if ( sTheInstance.mImmSetOpenStatus ) -		return sTheInstance.mImmSetOpenStatus(himc, status);  -	return FALSE; -} - -// static  -BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	 -{  -	if ( sTheInstance.mImmGetConversionStatus ) -		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence);  -	return FALSE; -} - -// static  -BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		 -{  -	if ( sTheInstance.mImmSetConversionStatus ) -		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence);  -	return FALSE; -} - -// static  -BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					 -{  -	if ( sTheInstance.mImmGetCompostitionWindow ) -		return sTheInstance.mImmGetCompostitionWindow(himc, form);	 -	return FALSE; -} - -// static  -BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					 -{  -	if ( sTheInstance.mImmSetCompostitionWindow ) -		return sTheInstance.mImmSetCompostitionWindow(himc, form);	 -	return FALSE; -} - - -// static  -LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					 -{  -	if ( sTheInstance.mImmGetCompositionString ) -		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	 -	return FALSE; -} - - -// static  -BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					 -{  -	if ( sTheInstance.mImmSetCompositionString ) -		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	 -	return FALSE; -} - -// static  -BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					 -{  -	if ( sTheInstance.mImmSetCompositionFont ) -		return sTheInstance.mImmSetCompositionFont(himc, pFont);	 -	return FALSE; -} - -// static  -BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					 -{  -	if ( sTheInstance.mImmSetCandidateWindow ) -		return sTheInstance.mImmSetCandidateWindow(himc, form);	 -	return FALSE; -} - -// static  -BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					 -{  -	if ( sTheInstance.mImmNotifyIME ) -		return sTheInstance.mImmNotifyIME(himc, action, index, value);	 -	return FALSE; -} - - - - -// ---------------------------------------------------------------------------------------- -LLWinImm::~LLWinImm() -{ -	if (mHImmDll != NULL) -	{ -		FreeLibrary(mHImmDll); -		mHImmDll = NULL; -	} -} - - -LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, -							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width, -							 S32 height, U32 flags,  -							 BOOL fullscreen, BOOL clearBg, -							 BOOL disable_vsync, BOOL use_gl, -							 BOOL ignore_pixel_depth, -							 U32 fsaa_samples) -	: LLWindow(callbacks, fullscreen, flags) -{ -	mFSAASamples = fsaa_samples; -	mIconResource = gIconResource; -	mOverrideAspectRatio = 0.f; -	mNativeAspectRatio = 0.f; -	mMousePositionModified = FALSE; -	mInputProcessingPaused = FALSE; -	mPreeditor = NULL; -	mhDC = NULL; -	mhRC = NULL; - -	// Initialize the keyboard -	gKeyboard = new LLKeyboardWin32(); -	gKeyboard->setCallbacks(callbacks); - -	// Initialize (boot strap) the Language text input management, -	// based on the system's (user's) default settings. -	allowLanguageTextInput(mPreeditor, FALSE); - -	WNDCLASS		wc; -	RECT			window_rect; - -	// Set the window title -	if (title.empty()) -	{ -		mWindowTitle = new WCHAR[50]; -		wsprintf(mWindowTitle, L"OpenGL Window"); -	} -	else -	{ -		mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. -		mbstowcs(mWindowTitle, title.c_str(), 255); -		mWindowTitle[255] = 0; -	} - -	// Set the window class name -	if (name.empty()) -	{ -		mWindowClassName = new WCHAR[50]; -		wsprintf(mWindowClassName, L"OpenGL Window"); -	} -	else -	{ -		mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. -		mbstowcs(mWindowClassName, name.c_str(), 255); -		mWindowClassName[255] = 0; -	} - - -	// We're not clipping yet -	SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - -	// Make an instance of our window then define the window class -	mhInstance = GetModuleHandle(NULL); -	mWndProc = NULL; - -	mSwapMethod = SWAP_METHOD_UNDEFINED; - -	// No WPARAM yet. -	mLastSizeWParam = 0; - -	// Windows GDI rects don't include rightmost pixel -	window_rect.left = (long) 0; -	window_rect.right = (long) width; -	window_rect.top = (long) 0; -	window_rect.bottom = (long) height; - -	// Grab screen size to sanitize the window -	S32 window_border_y = GetSystemMetrics(SM_CYBORDER); -	S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN);  -	S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN);  -	S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); -	S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - -	if (x < virtual_screen_x) x = virtual_screen_x; -	if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; - -	if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; -	if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; - -	if (!sIsClassRegistered) -	{ -		// Force redraw when resized and create a private device context - -		// Makes double click messages. -		wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - -		// Set message handler function -		wc.lpfnWndProc = (WNDPROC) mainWindowProc; - -		// unused -		wc.cbClsExtra = 0; -		wc.cbWndExtra = 0; - -		wc.hInstance = mhInstance; -		wc.hIcon = LoadIcon(mhInstance, mIconResource); - -		// We will set the cursor ourselves -		wc.hCursor = NULL; - -		// background color is not used -		if (clearBg) -		{ -			wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); -		} -		else -		{ -			wc.hbrBackground = (HBRUSH) NULL; -		} - -		// we don't use windows menus -		wc.lpszMenuName = NULL; - -		wc.lpszClassName = mWindowClassName; - -		if (!RegisterClass(&wc)) -		{ -			OSMessageBox(mCallbacks->translateString("MBRegClassFailed"),  -				mCallbacks->translateString("MBError"), OSMB_OK); -			return; -		} -		sIsClassRegistered = TRUE; -	} - -	//----------------------------------------------------------------------- -	// Get the current refresh rate -	//----------------------------------------------------------------------- - -	DEVMODE dev_mode; -	DWORD current_refresh; -	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) -	{ -		current_refresh = dev_mode.dmDisplayFrequency; -		mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); -	} -	else -	{ -		current_refresh = 60; -	} - -	//----------------------------------------------------------------------- -	// Drop resolution and go fullscreen -	// use a display mode with our desired size and depth, with a refresh -	// rate as close at possible to the users' default -	//----------------------------------------------------------------------- -	if (mFullscreen) -	{ -		BOOL success = FALSE; -		DWORD closest_refresh = 0; - -		for (S32 mode_num = 0;; mode_num++) -		{ -			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) -			{ -				break; -			} - -			if (dev_mode.dmPelsWidth == width && -				dev_mode.dmPelsHeight == height && -				dev_mode.dmBitsPerPel == BITS_PER_PIXEL) -			{ -				success = TRUE; -				if ((dev_mode.dmDisplayFrequency - current_refresh) -					< (closest_refresh - current_refresh)) -				{ -					closest_refresh = dev_mode.dmDisplayFrequency; -				} -			} -		} - -		if (closest_refresh == 0) -		{ -			LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; -			success = FALSE; -		} - -		// If we found a good resolution, use it. -		if (success) -		{ -			success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); -		} - -		// Keep a copy of the actual current device mode in case we minimize  -		// and change the screen resolution.   JC -		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - -		// If it failed, we don't want to run fullscreen -		if (success) -		{ -			mFullscreen = TRUE; -			mFullscreenWidth   = dev_mode.dmPelsWidth; -			mFullscreenHeight  = dev_mode.dmPelsHeight; -			mFullscreenBits    = dev_mode.dmBitsPerPel; -			mFullscreenRefresh = dev_mode.dmDisplayFrequency; - -			LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth -				<< "x"   << dev_mode.dmPelsHeight -				<< "x"   << dev_mode.dmBitsPerPel -				<< " @ " << dev_mode.dmDisplayFrequency -				<< LL_ENDL; -		} -		else -		{ -			mFullscreen = FALSE; -			mFullscreenWidth   = -1; -			mFullscreenHeight  = -1; -			mFullscreenBits    = -1; -			mFullscreenRefresh = -1; - -			std::map<std::string,std::string> args; -			args["[WIDTH]"] = llformat("%d", width); -			args["[HEIGHT]"] = llformat ("%d", height); -			OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), -				mCallbacks->translateString("MBError"), OSMB_OK); -		} -	} - -	// TODO: add this after resolving _WIN32_WINNT issue -	//	if (!fullscreen) -	//	{ -	//		TRACKMOUSEEVENT track_mouse_event; -	//		track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); -	//		track_mouse_event.dwFlags = TME_LEAVE; -	//		track_mouse_event.hwndTrack = mWindowHandle; -	//		track_mouse_event.dwHoverTime = HOVER_DEFAULT; -	//		TrackMouseEvent( &track_mouse_event );  -	//	} - - -	//----------------------------------------------------------------------- -	// Create GL drawing context -	//----------------------------------------------------------------------- -	LLCoordScreen windowPos(x,y); -	LLCoordScreen windowSize(window_rect.right - window_rect.left, -							 window_rect.bottom - window_rect.top); -	if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos)) -	{ -		return; -	} -	 -	//start with arrow cursor -	initCursors(); -	setCursor( UI_CURSOR_ARROW ); - -	// Initialize (boot strap) the Language text input management, -	// based on the system's (or user's) default settings. -	allowLanguageTextInput(NULL, FALSE); -} - - -LLWindowWin32::~LLWindowWin32() -{ -	delete [] mWindowTitle; -	mWindowTitle = NULL; - -	delete [] mSupportedResolutions; -	mSupportedResolutions = NULL; - -	delete mWindowClassName; -	mWindowClassName = NULL; -} - -void LLWindowWin32::show() -{ -	ShowWindow(mWindowHandle, SW_SHOW); -	SetForegroundWindow(mWindowHandle); -	SetFocus(mWindowHandle); -} - -void LLWindowWin32::hide() -{ -	setMouseClipping(FALSE); -	ShowWindow(mWindowHandle, SW_HIDE); -} - -void LLWindowWin32::minimize() -{ -	setMouseClipping(FALSE); -	showCursor(); -	ShowWindow(mWindowHandle, SW_MINIMIZE); -} - - -void LLWindowWin32::restore() -{ -	ShowWindow(mWindowHandle, SW_RESTORE); -	SetForegroundWindow(mWindowHandle); -	SetFocus(mWindowHandle); -} - - -// close() destroys all OS-specific code associated with a window. -// Usually called from LLWindowManager::destroyWindow() -void LLWindowWin32::close() -{ -	LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; -	// Is window is already closed? -	if (!mWindowHandle) -	{ -		return; -	} - -	// Make sure cursor is visible and we haven't mangled the clipping state. -	setMouseClipping(FALSE); -	showCursor(); - -	// Go back to screen mode written in the registry. -	if (mFullscreen) -	{ -		resetDisplayResolution(); -	} - -	// Clean up remaining GL state -	LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL; -	gGLManager.shutdownGL(); - -	LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; -	if (mhRC) -	{ -		if (!wglMakeCurrent(NULL, NULL)) -		{ -			LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; -		} - -		if (!wglDeleteContext(mhRC)) -		{ -			LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; -		} - -		mhRC = NULL; -	} - -	// Restore gamma to the system values. -	restoreGamma(); - -	if (mhDC && !ReleaseDC(mWindowHandle, mhDC)) -	{ -		LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL; -		mhDC = NULL; -	} - -	LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; -	 -	// Don't process events in our mainWindowProc any longer. -	SetWindowLong(mWindowHandle, GWL_USERDATA, NULL); - -	// Make sure we don't leave a blank toolbar button. -	ShowWindow(mWindowHandle, SW_HIDE); - -	// This causes WM_DESTROY to be sent *immediately* -	if (!DestroyWindow(mWindowHandle)) -	{ -		OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), -			mCallbacks->translateString("MBShutdownErr"), -			OSMB_OK); -	} - -	mWindowHandle = NULL; -} - -BOOL LLWindowWin32::isValid() -{ -	return (mWindowHandle != NULL); -} - -BOOL LLWindowWin32::getVisible() -{ -	return (mWindowHandle && IsWindowVisible(mWindowHandle)); -} - -BOOL LLWindowWin32::getMinimized() -{ -	return (mWindowHandle && IsIconic(mWindowHandle)); -} - -BOOL LLWindowWin32::getMaximized() -{ -	return (mWindowHandle && IsZoomed(mWindowHandle)); -} - -BOOL LLWindowWin32::maximize() -{ -	BOOL success = FALSE; -	if (!mWindowHandle) return success; - -	WINDOWPLACEMENT placement; -	placement.length = sizeof(WINDOWPLACEMENT); - -	success = GetWindowPlacement(mWindowHandle, &placement); -	if (!success) return success; - -	placement.showCmd = SW_MAXIMIZE; - -	success = SetWindowPlacement(mWindowHandle, &placement); -	return success; -} - -BOOL LLWindowWin32::getFullscreen() -{ -	return mFullscreen; -} - -BOOL LLWindowWin32::getPosition(LLCoordScreen *position) -{ -	RECT window_rect; - -	if (!mWindowHandle || -		!GetWindowRect(mWindowHandle, &window_rect) || -		NULL == position) -	{ -		return FALSE; -	} - -	position->mX = window_rect.left; -	position->mY = window_rect.top; -	return TRUE; -} - -BOOL LLWindowWin32::getSize(LLCoordScreen *size) -{ -	RECT window_rect; - -	if (!mWindowHandle || -		!GetWindowRect(mWindowHandle, &window_rect) || -		NULL == size) -	{ -		return FALSE; -	} - -	size->mX = window_rect.right - window_rect.left; -	size->mY = window_rect.bottom - window_rect.top; -	return TRUE; -} - -BOOL LLWindowWin32::getSize(LLCoordWindow *size) -{ -	RECT client_rect; - -	if (!mWindowHandle || -		!GetClientRect(mWindowHandle, &client_rect) || -		NULL == size) -	{ -		return FALSE; -	} - -	size->mX = client_rect.right - client_rect.left; -	size->mY = client_rect.bottom - client_rect.top; -	return TRUE; -} - -BOOL LLWindowWin32::setPosition(const LLCoordScreen position) -{ -	LLCoordScreen size; - -	if (!mWindowHandle) -	{ -		return FALSE; -	} -	getSize(&size); -	moveWindow(position, size); -	return TRUE; -} - -BOOL LLWindowWin32::setSize(const LLCoordScreen size) -{ -	LLCoordScreen position; - -	getPosition(&position); -	if (!mWindowHandle) -	{ -		return FALSE; -	} - -	moveWindow(position, size); -	return TRUE; -} - -// changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) -{ -	GLuint	pixel_format; -	DEVMODE dev_mode; -	DWORD	current_refresh; -	DWORD	dw_ex_style; -	DWORD	dw_style; -	RECT	window_rect; -	S32 width = size.mX; -	S32 height = size.mY; -	BOOL auto_show = FALSE; - -	if (mhRC) -	{ -		auto_show = TRUE; -		resetDisplayResolution(); -	} - -	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) -	{ -		current_refresh = dev_mode.dmDisplayFrequency; -	} -	else -	{ -		current_refresh = 60; -	} - -	gGLManager.shutdownGL(); -	//destroy gl context -	if (mhRC) -	{ -		if (!wglMakeCurrent(NULL, NULL)) -		{ -			LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; -		} - -		if (!wglDeleteContext(mhRC)) -		{ -			LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; -		} - -		mhRC = NULL; -	} - -	if (fullscreen) -	{ -		mFullscreen = TRUE; -		BOOL success = FALSE; -		DWORD closest_refresh = 0; - -		for (S32 mode_num = 0;; mode_num++) -		{ -			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) -			{ -				break; -			} - -			if (dev_mode.dmPelsWidth == width && -				dev_mode.dmPelsHeight == height && -				dev_mode.dmBitsPerPel == BITS_PER_PIXEL) -			{ -				success = TRUE; -				if ((dev_mode.dmDisplayFrequency - current_refresh) -					< (closest_refresh - current_refresh)) -				{ -					closest_refresh = dev_mode.dmDisplayFrequency; -				} -			} -		} - -		if (closest_refresh == 0) -		{ -			LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; -			return FALSE; -		} - -		// If we found a good resolution, use it. -		if (success) -		{ -			success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); -		} - -		// Keep a copy of the actual current device mode in case we minimize  -		// and change the screen resolution.   JC -		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - -		if (success) -		{ -			mFullscreen = TRUE; -			mFullscreenWidth   = dev_mode.dmPelsWidth; -			mFullscreenHeight  = dev_mode.dmPelsHeight; -			mFullscreenBits    = dev_mode.dmBitsPerPel; -			mFullscreenRefresh = dev_mode.dmDisplayFrequency; - -			LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth -				<< "x"   << dev_mode.dmPelsHeight -				<< "x"   << dev_mode.dmBitsPerPel -				<< " @ " << dev_mode.dmDisplayFrequency -				<< LL_ENDL; - -			window_rect.left = (long) 0; -			window_rect.right = (long) width;			// Windows GDI rects don't include rightmost pixel -			window_rect.top = (long) 0; -			window_rect.bottom = (long) height; -			dw_ex_style = WS_EX_APPWINDOW; -			dw_style = WS_POPUP; - -			// Move window borders out not to cover window contents -			AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); -		} -		// If it failed, we don't want to run fullscreen -		else -		{ -			mFullscreen = FALSE; -			mFullscreenWidth   = -1; -			mFullscreenHeight  = -1; -			mFullscreenBits    = -1; -			mFullscreenRefresh = -1; - -			LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; -			return FALSE; -		} -	} -	else -	{ -		mFullscreen = FALSE; -		window_rect.left = (long) (posp ? posp->mX : 0); -		window_rect.right = (long) width + window_rect.left;			// Windows GDI rects don't include rightmost pixel -		window_rect.top = (long) (posp ? posp->mY : 0); -		window_rect.bottom = (long) height + window_rect.top; -		// Window with an edge -		dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; -		dw_style = WS_OVERLAPPEDWINDOW; -	} - -	// don't post quit messages when destroying old windows -	mPostQuit = FALSE; - -	// create window -	DestroyWindow(mWindowHandle); -	mWindowHandle = CreateWindowEx(dw_ex_style, -		mWindowClassName, -		mWindowTitle, -		WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, -		window_rect.left,								// x pos -		window_rect.top,								// y pos -		window_rect.right - window_rect.left,			// width -		window_rect.bottom - window_rect.top,			// height -		NULL, -		NULL, -		mhInstance, -		NULL); - -	//----------------------------------------------------------------------- -	// Create GL drawing context -	//----------------------------------------------------------------------- -	static PIXELFORMATDESCRIPTOR pfd = -	{ -		sizeof(PIXELFORMATDESCRIPTOR),  -			1, -			PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,  -			PFD_TYPE_RGBA, -			BITS_PER_PIXEL, -			0, 0, 0, 0, 0, 0,	// RGB bits and shift, unused -			8,					// alpha bits -			0,					// alpha shift -			0,					// accum bits -			0, 0, 0, 0,			// accum RGBA -			24,					// depth bits -			8,					// stencil bits, avi added for stencil test -			0, -			PFD_MAIN_PLANE, -			0, -			0, 0, 0 -	}; - -	if (!(mhDC = GetDC(mWindowHandle))) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBDevContextErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd))) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	// Verify what pixel format we actually received. -	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), -		&pfd)) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (pfd.cColorBits < 32) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (pfd.cAlphaBits < 8) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBAlpha"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!SetPixelFormat(mhDC, pixel_format, &pfd)) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!(mhRC = wglCreateContext(mhDC))) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBGLContextErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!wglMakeCurrent(mhDC, mhRC)) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), -			mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	gGLManager.initWGL(); - -	if (wglChoosePixelFormatARB) -	{ -		// OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we -		// can get exactly what we want. -		GLint attrib_list[256]; -		S32 cur_attrib = 0; - -		attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; -		attrib_list[cur_attrib++] = 24; - -		attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; -		attrib_list[cur_attrib++] = 8; - -		attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; -		attrib_list[cur_attrib++] = GL_TRUE; - -		attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; -		attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; - -		attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; -		attrib_list[cur_attrib++] = GL_TRUE; - -		attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; -		attrib_list[cur_attrib++] = GL_TRUE; - -		attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; -		attrib_list[cur_attrib++] = 24; - -		attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; -		attrib_list[cur_attrib++] = 8; - -		U32 end_attrib = 0; -		if (mFSAASamples > 0) -		{ -			end_attrib = cur_attrib; -			attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; -			attrib_list[cur_attrib++] = GL_TRUE; - -			attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; -			attrib_list[cur_attrib++] = mFSAASamples; -		} - -		// End the list -		attrib_list[cur_attrib++] = 0; - -		GLint pixel_formats[256]; -		U32 num_formats = 0; - -		// First we try and get a 32 bit depth pixel format -		BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); -		if (!result) -		{ -			close(); -			show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); -			return FALSE; -		} - -		if (!num_formats) -		{ -			if (end_attrib > 0) -			{ -				LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; -				attrib_list[end_attrib] = 0; - -				BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); -				if (!result) -				{ -					close(); -					show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); -					return FALSE; -				} -			} - -			if (!num_formats) -			{ -				LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; -				// Try 24-bit format -				attrib_list[1] = 24; -				BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); -				if (!result) -				{ -					close(); -					show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); -					return FALSE; -				} - -				if (!num_formats) -				{ -					LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; -					attrib_list[1] = 16; -					BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); -					if (!result || !num_formats) -					{ -						close(); -						show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); -						return FALSE; -					} -				} -			} - -			LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; -		} - -		 - -		S32 swap_method = 0; -		S32 cur_format = num_formats-1; -		GLint swap_query = WGL_SWAP_METHOD_ARB; - -		BOOL found_format = FALSE; - -		while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) -		{ -			if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0) -			{ -				found_format = TRUE; -			} -			else -			{ -				--cur_format; -			} -		} -		 -		pixel_format = pixel_formats[cur_format]; -		 -		if (mhDC != 0)											// Does The Window Have A Device Context? -		{ -			wglMakeCurrent(mhDC, 0);							// Set The Current Active Rendering Context To Zero -			if (mhRC != 0)										// Does The Window Have A Rendering Context? -			{ -				wglDeleteContext (mhRC);							// Release The Rendering Context -				mhRC = 0;										// Zero The Rendering Context - -			} -			ReleaseDC (mWindowHandle, mhDC);						// Release The Device Context -			mhDC = 0;											// Zero The Device Context -		} -		DestroyWindow (mWindowHandle);									// Destroy The Window -		 - -		mWindowHandle = CreateWindowEx(dw_ex_style, -			mWindowClassName, -			mWindowTitle, -			WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, -			window_rect.left,								// x pos -			window_rect.top,								// y pos -			window_rect.right - window_rect.left,			// width -			window_rect.bottom - window_rect.top,			// height -			NULL, -			NULL, -			mhInstance, -			NULL); - -		if (!(mhDC = GetDC(mWindowHandle))) -		{ -			close(); -			OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); -			return FALSE; -		} - -		if (!SetPixelFormat(mhDC, pixel_format, &pfd)) -		{ -			close(); -			OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), -				mCallbacks->translateString("MBError"), OSMB_OK); -			return FALSE; -		} - -		if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) -		{ -			switch (swap_method) -			{ -			case WGL_SWAP_EXCHANGE_ARB: -				mSwapMethod = SWAP_METHOD_EXCHANGE; -				LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; -				break; -			case WGL_SWAP_COPY_ARB: -				mSwapMethod = SWAP_METHOD_COPY; -				LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; -				break; -			case WGL_SWAP_UNDEFINED_ARB: -				mSwapMethod = SWAP_METHOD_UNDEFINED; -				LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; -				break; -			default: -				mSwapMethod = SWAP_METHOD_UNDEFINED; -				LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; -				break; -			} -		}		 -	} -	else -	{ -		LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL; -	} - -	// Verify what pixel format we actually received. -	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), -		&pfd)) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits)  -		<< " Alpha Bits " << S32(pfd.cAlphaBits) -		<< " Depth Bits " << S32(pfd.cDepthBits)  -		<< LL_ENDL; - -	// make sure we have 32 bits per pixel -	if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (pfd.cAlphaBits < 8) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!(mhRC = wglCreateContext(mhDC))) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!wglMakeCurrent(mhDC, mhRC)) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	if (!gGLManager.initGL()) -	{ -		close(); -		OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); -		return FALSE; -	} - -	// Disable vertical sync for swap -	if (disable_vsync && wglSwapIntervalEXT) -	{ -		LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; -		wglSwapIntervalEXT(0); -	} -	else -	{ -		LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; -	} - -	SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this); -	 -	//register joystick timer callback -	SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer - -	// ok to post quit messages now -	mPostQuit = TRUE; - -	if (auto_show) -	{ -		show(); -		glClearColor(0.0f, 0.0f, 0.0f, 0.f); -		glClear(GL_COLOR_BUFFER_BIT); -		swapBuffers(); -	} - -	return TRUE; -} - -void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) -{ -	if( mIsMouseClipping ) -	{ -		RECT client_rect_in_screen_space; -		if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) -		{ -			ClipCursor( &client_rect_in_screen_space ); -		} -	} - -	// if the window was already maximized, MoveWindow seems to still set the maximized flag even if -	// the window is smaller than maximized. -	// So we're going to do a restore first (which is a ShowWindow call) (SL-44655). - -	// THIS CAUSES DEV-15484 and DEV-15949  -	//ShowWindow(mWindowHandle, SW_RESTORE); -	// NOW we can call MoveWindow -	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); -} - -BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) -{ -	LLCoordScreen screen_pos; - -	mMousePositionModified = TRUE; -	if (!mWindowHandle) -	{ -		return FALSE; -	} - -	if (!convertCoords(position, &screen_pos)) -	{ -		return FALSE; -	} - -	// Inform the application of the new mouse position (needed for per-frame -	// hover/picking to function). -	LLCoordGL gl_pos; -	convertCoords(position, &gl_pos); -	mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); -	 -	// DEV-18951 VWR-8524 Camera moves wildly when alt-clicking. -	// Because we have preemptively notified the application of the new -	// mouse position via handleMouseMove() above, we need to clear out -	// any stale mouse move events.  RN/JC -	MSG msg; -	while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) -	{ } - -	return SetCursorPos(screen_pos.mX, screen_pos.mY); -} - -BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) -{ -	POINT cursor_point; -	LLCoordScreen screen_pos; - -	if (!mWindowHandle || -		!GetCursorPos(&cursor_point)) -	{ -		return FALSE; -	} - -	screen_pos.mX = cursor_point.x; -	screen_pos.mY = cursor_point.y; - -	return convertCoords(screen_pos, position); -} - -void LLWindowWin32::hideCursor() -{ -	while (ShowCursor(FALSE) >= 0) -	{ -		// nothing, wait for cursor to push down -	} -	mCursorHidden = TRUE; -	mHideCursorPermanent = TRUE; -} - -void LLWindowWin32::showCursor() -{ -	// makes sure the cursor shows up -	while (ShowCursor(TRUE) < 0) -	{ -		// do nothing, wait for cursor to pop out -	} -	mCursorHidden = FALSE; -	mHideCursorPermanent = FALSE; -} - -void LLWindowWin32::showCursorFromMouseMove() -{ -	if (!mHideCursorPermanent) -	{ -		showCursor(); -	} -} - -void LLWindowWin32::hideCursorUntilMouseMove() -{ -	if (!mHideCursorPermanent) -	{ -		hideCursor(); -		mHideCursorPermanent = FALSE; -	} -} - -BOOL LLWindowWin32::isCursorHidden() -{ -	return mCursorHidden; -} - - -HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) -{ -	return (HCURSOR)LoadImage(mhInstance, -							  name, -							  IMAGE_CURSOR, -							  0,	// default width -							  0,	// default height -							  LR_DEFAULTCOLOR); -} - - -void LLWindowWin32::initCursors() -{ -	mCursor[ UI_CURSOR_ARROW ]		= LoadCursor(NULL, IDC_ARROW); -	mCursor[ UI_CURSOR_WAIT ]		= LoadCursor(NULL, IDC_WAIT); -	mCursor[ UI_CURSOR_HAND ]		= LoadCursor(NULL, IDC_HAND); -	mCursor[ UI_CURSOR_IBEAM ]		= LoadCursor(NULL, IDC_IBEAM); -	mCursor[ UI_CURSOR_CROSS ]		= LoadCursor(NULL, IDC_CROSS); -	mCursor[ UI_CURSOR_SIZENWSE ]	= LoadCursor(NULL, IDC_SIZENWSE); -	mCursor[ UI_CURSOR_SIZENESW ]	= LoadCursor(NULL, IDC_SIZENESW); -	mCursor[ UI_CURSOR_SIZEWE ]		= LoadCursor(NULL, IDC_SIZEWE);   -	mCursor[ UI_CURSOR_SIZENS ]		= LoadCursor(NULL, IDC_SIZENS);   -	mCursor[ UI_CURSOR_NO ]			= LoadCursor(NULL, IDC_NO); -	mCursor[ UI_CURSOR_WORKING ]	= LoadCursor(NULL, IDC_APPSTARTING);  - -	HMODULE module = GetModuleHandle(NULL); -	mCursor[ UI_CURSOR_TOOLGRAB ]	= LoadCursor(module, TEXT("TOOLGRAB")); -	mCursor[ UI_CURSOR_TOOLLAND ]	= LoadCursor(module, TEXT("TOOLLAND")); -	mCursor[ UI_CURSOR_TOOLFOCUS ]	= LoadCursor(module, TEXT("TOOLFOCUS")); -	mCursor[ UI_CURSOR_TOOLCREATE ]	= LoadCursor(module, TEXT("TOOLCREATE")); -	mCursor[ UI_CURSOR_ARROWDRAG ]	= LoadCursor(module, TEXT("ARROWDRAG")); -	mCursor[ UI_CURSOR_ARROWCOPY ]	= LoadCursor(module, TEXT("ARROWCOPY")); -	mCursor[ UI_CURSOR_ARROWDRAGMULTI ]	= LoadCursor(module, TEXT("ARROWDRAGMULTI")); -	mCursor[ UI_CURSOR_ARROWCOPYMULTI ]	= LoadCursor(module, TEXT("ARROWCOPYMULTI")); -	mCursor[ UI_CURSOR_NOLOCKED ]	= LoadCursor(module, TEXT("NOLOCKED")); -	mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); -	mCursor[ UI_CURSOR_GRABLOCKED ]	= LoadCursor(module, TEXT("GRABLOCKED")); -	mCursor[ UI_CURSOR_TOOLTRANSLATE ]	= LoadCursor(module, TEXT("TOOLTRANSLATE")); -	mCursor[ UI_CURSOR_TOOLROTATE ]	= LoadCursor(module, TEXT("TOOLROTATE"));  -	mCursor[ UI_CURSOR_TOOLSCALE ]	= LoadCursor(module, TEXT("TOOLSCALE")); -	mCursor[ UI_CURSOR_TOOLCAMERA ]	= LoadCursor(module, TEXT("TOOLCAMERA")); -	mCursor[ UI_CURSOR_TOOLPAN ]	= LoadCursor(module, TEXT("TOOLPAN")); -	mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); -	mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); -	mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); - -	// Color cursors -	mCursor[UI_CURSOR_TOOLPLAY] = loadColorCursor(TEXT("TOOLPLAY")); -	mCursor[UI_CURSOR_TOOLPAUSE] = loadColorCursor(TEXT("TOOLPAUSE")); -	mCursor[UI_CURSOR_TOOLMEDIAOPEN] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); - -	// Note: custom cursors that are not found make LoadCursor() return NULL. -	for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) -	{ -		if( !mCursor[i] ) -		{ -			mCursor[i] = LoadCursor(NULL, IDC_ARROW); -		} -	} -} - - - -void LLWindowWin32::setCursor(ECursorType cursor) -{ -	if (cursor == UI_CURSOR_ARROW -		&& mBusyCount > 0) -	{ -		cursor = UI_CURSOR_WORKING; -	} - -	if( mCurrentCursor != cursor ) -	{ -		mCurrentCursor = cursor; -		SetCursor( mCursor[cursor] ); -	} -} - -ECursorType LLWindowWin32::getCursor() const -{ -	return mCurrentCursor; -} - -void LLWindowWin32::captureMouse() -{ -	SetCapture(mWindowHandle); -} - -void LLWindowWin32::releaseMouse() -{ -	// *NOTE:Mani ReleaseCapture will spawn new windows messages... -	// which will in turn call our MainWindowProc. It therefore requires -	// pausing *and more importantly resumption* of the mainlooptimeout... -	// just like DispatchMessage below. -	mCallbacks->handlePauseWatchdog(this); -	ReleaseCapture(); -	mCallbacks->handleResumeWatchdog(this); -} - - -void LLWindowWin32::delayInputProcessing() -{ -	mInputProcessingPaused = TRUE; -} - -void LLWindowWin32::gatherInput() -{ -	MSG		msg; -	int		msg_count = 0; - -	LLMemType m1(LLMemType::MTYPE_GATHER_INPUT); - -	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE) -	{ -		mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput"); -		TranslateMessage(&msg); - -		// turn watchdog off in here to not fail if windows is doing something wacky -		mCallbacks->handlePauseWatchdog(this); -		DispatchMessage(&msg); -		mCallbacks->handleResumeWatchdog(this); -		msg_count++; - -		if ( mInputProcessingPaused ) -		{ -			break; -		} -		/* Attempted workaround for problem where typing fast and hitting -		   return would result in only part of the text being sent. JC - -		BOOL key_posted = TranslateMessage(&msg); -		DispatchMessage(&msg); -		msg_count++; - -		// If a key was translated, a WM_CHAR might have been posted to the end -		// of the event queue.  We need it immediately. -		if (key_posted && msg.message == WM_KEYDOWN) -		{ -			if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) -			{ -				TranslateMessage(&msg); -				DispatchMessage(&msg); -				msg_count++; -			} -		} -		*/ -		mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput"); -		// For async host by name support.  Really hacky. -		if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) -		{ -			gAsyncMsgCallback(msg); -		} -	} - -	mInputProcessingPaused = FALSE; - -	// clear this once we've processed all mouse messages that might have occurred after -	// we slammed the mouse position -	mMousePositionModified = FALSE; -} - -static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard"); -static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse"); - -LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) -{ -	LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA); - - -	if (NULL != window_imp) -	{ -		window_imp->mCallbacks->handleResumeWatchdog(window_imp); -		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc"); -		// Has user provided their own window callback? -		if (NULL != window_imp->mWndProc) -		{ -			if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) -			{ -				// user has handled window message -				return 0; -			} -		} - -		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc"); -		 -		// Juggle to make sure we can get negative positions for when -		// mouse is outside window. -		LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); - -		// This doesn't work, as LOWORD returns unsigned short. -		//LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); -		LLCoordGL gl_coord; - -		// pass along extended flag in mask -		MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; -		BOOL eat_keystroke = TRUE; - -		switch(u_msg) -		{ -			RECT	update_rect; -			S32		update_width; -			S32		update_height; - -		case WM_TIMER: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER"); -			window_imp->mCallbacks->handleTimerEvent(window_imp); -			break; - -		case WM_DEVICECHANGE: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE"); -			if (gDebugWindowProc) -			{ -				llinfos << "  WM_DEVICECHANGE: wParam=" << w_param  -						<< "; lParam=" << l_param << llendl; -			} -			if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) -			{ -				if (window_imp->mCallbacks->handleDeviceChange(window_imp)) -				{ -					return 0; -				} -			} -			break; - -		case WM_PAINT: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT"); -			GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); -			update_width = update_rect.right - update_rect.left + 1; -			update_height = update_rect.bottom - update_rect.top + 1; -			window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, -				update_width, update_height); -			break; -		case WM_PARENTNOTIFY: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY"); -			u_msg = u_msg; -			break; - -		case WM_SETCURSOR: -			// This message is sent whenever the cursor is moved in a window. -			// You need to set the appropriate cursor appearance. - -			// Only take control of cursor over client region of window -			// This allows Windows(tm) to handle resize cursors, etc. -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR"); -			if (LOWORD(l_param) == HTCLIENT) -			{ -				SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] ); -				return 0; -			} -			break; - -		case WM_ENTERMENULOOP: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP"); -			window_imp->mCallbacks->handleWindowBlock(window_imp); -			break; - -		case WM_EXITMENULOOP: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP"); -			window_imp->mCallbacks->handleWindowUnblock(window_imp); -			break; - -		case WM_ACTIVATEAPP: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP"); -			{ -				// This message should be sent whenever the app gains or loses focus. -				BOOL activating = (BOOL) w_param; -				BOOL minimized = window_imp->getMinimized(); - -				if (gDebugWindowProc) -				{ -					LL_INFOS("Window") << "WINDOWPROC ActivateApp " -						<< " activating " << S32(activating) -						<< " minimized " << S32(minimized) -						<< " fullscreen " << S32(window_imp->mFullscreen) -						<< LL_ENDL; -				} - -				if (window_imp->mFullscreen) -				{ -					// When we run fullscreen, restoring or minimizing the app needs  -					// to switch the screen resolution -					if (activating) -					{ -						window_imp->setFullscreenResolution(); -						window_imp->restore(); -					} -					else -					{ -						window_imp->minimize(); -						window_imp->resetDisplayResolution(); -					} -				} - -				window_imp->mCallbacks->handleActivateApp(window_imp, activating); - -				break; -			} - -		case WM_ACTIVATE: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE"); -			{ -				// Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE -				BOOL activating = (LOWORD(w_param) != WA_INACTIVE); - -				BOOL minimized = BOOL(HIWORD(w_param)); - -				if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) -				{ -					window_imp->interruptLanguageTextInput(); -				} - -				// JC - I'm not sure why, but if we don't report that we handled the  -				// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work  -				// properly when we run fullscreen. -				if (gDebugWindowProc) -				{ -					LL_INFOS("Window") << "WINDOWPROC Activate " -						<< " activating " << S32(activating)  -						<< " minimized " << S32(minimized) -						<< LL_ENDL; -				} - -				// Don't handle this. -				break; -			} - -		case WM_QUERYOPEN: -			// TODO: use this to return a nice icon -			break; - -		case WM_SYSCOMMAND: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND"); -			switch(w_param) -			{ -			case SC_KEYMENU:  -				// Disallow the ALT key from triggering the default system menu. -				return 0;		 - -			case SC_SCREENSAVE: -			case SC_MONITORPOWER: -				// eat screen save messages and prevent them! -				return 0; -			} -			break; - -		case WM_CLOSE: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE"); -			// Will the app allow the window to close? -			if (window_imp->mCallbacks->handleCloseRequest(window_imp)) -			{ -				// Get the app to initiate cleanup. -				window_imp->mCallbacks->handleQuit(window_imp); -				// The app is responsible for calling destroyWindow when done with GL -			} -			return 0; - -		case WM_DESTROY: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY"); -			if (window_imp->shouldPostQuit()) -			{ -				PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0 -			} -			return 0; - -		case WM_COMMAND: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND"); -			if (!HIWORD(w_param)) // this message is from a menu -			{ -				window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)); -			} -			break; - -		case WM_SYSKEYDOWN: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN"); -			// allow system keys, such as ALT-F4 to be processed by Windows -			eat_keystroke = FALSE; -		case WM_KEYDOWN: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); -			{ -				if (gDebugWindowProc) -				{ -					LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " -						<< " key " << S32(w_param)  -						<< LL_ENDL; -				} -				if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) -				{ -					return 0; -				} -				// pass on to windows if we didn't handle it -				break; -			} -		case WM_SYSKEYUP: -			eat_keystroke = FALSE; -		case WM_KEYUP: -		{ -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); -			LLFastTimer t2(FTM_KEYHANDLER); - -			if (gDebugWindowProc) -			{ -				LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " -					<< " key " << S32(w_param)  -					<< LL_ENDL; -			} -			if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) -			{ -				return 0; -			} - -			// pass on to windows -			break; -		} -		case WM_IME_SETCONTEXT: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT"); -			if (gDebugWindowProc) -			{ -				llinfos << "WM_IME_SETCONTEXT" << llendl; -			} -			if (LLWinImm::isAvailable() && window_imp->mPreeditor) -			{ -				l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; -				// Invoke DefWinProc with the modified LPARAM. -			} -			break; - -		case WM_IME_STARTCOMPOSITION: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION"); -			if (gDebugWindowProc) -			{ -				llinfos << "WM_IME_STARTCOMPOSITION" << llendl; -			} -			if (LLWinImm::isAvailable() && window_imp->mPreeditor) -			{ -				window_imp->handleStartCompositionMessage(); -				return 0; -			} -			break; - -		case WM_IME_ENDCOMPOSITION: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION"); -			if (gDebugWindowProc) -			{ -				llinfos << "WM_IME_ENDCOMPOSITION" << llendl; -			} -			if (LLWinImm::isAvailable() && window_imp->mPreeditor) -			{ -				return 0; -			} -			break; - -		case WM_IME_COMPOSITION: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION"); -			if (gDebugWindowProc) -			{ -				llinfos << "WM_IME_COMPOSITION" << llendl; -			} -			if (LLWinImm::isAvailable() && window_imp->mPreeditor) -			{ -				window_imp->handleCompositionMessage(l_param); -				return 0; -			} -			break; - -		case WM_IME_REQUEST: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST"); -			if (gDebugWindowProc) -			{ -				llinfos << "WM_IME_REQUEST" << llendl; -			} -			if (LLWinImm::isAvailable() && window_imp->mPreeditor) -			{ -				LRESULT result = 0; -				if (window_imp->handleImeRequests(w_param, l_param, &result)) -				{ -					return result; -				} -			} -			break; - -		case WM_CHAR: -			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need -			// to figure out how that works. - Doug -			// -			// ... Well, I don't think so. -			// How it works is explained in Win32 API document, but WM_UNICHAR didn't work -			// as specified at least on Windows XP SP1 Japanese version.  I have never used -			// it since then, and I'm not sure whether it has been fixed now, but I don't think -			// it is worth trying.  The good old WM_CHAR works just fine even for supplementary -			// characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's -			// by ourselves.  It is not that tough.  -- Alissa Sabre @ SL -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); -			if (gDebugWindowProc) -			{ -				LL_INFOS("Window") << "Debug WindowProc WM_CHAR " -					<< " key " << S32(w_param)  -					<< LL_ENDL; -			} -			// Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, -			// we *did* processed the event, so I believe we should not pass it to DefWindowProc... -			window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); -			return 0; - -		case WM_LBUTTONDOWN: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				if (LLWinImm::isAvailable() && window_imp->mPreeditor) -				{ -					window_imp->interruptLanguageTextInput(); -				} - -				// Because we move the cursor position in the app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_LBUTTONDBLCLK: -		//RN: ignore right button double clicks for now -		//case WM_RBUTTONDBLCLK: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK"); -				// Because we move the cursor position in the app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) ) -				{ -					return 0; -				} -			} -			break; - -		case WM_LBUTTONUP: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				//if (gDebugClicks) -				//{ -				//	LL_INFOS("Window") << "WndProc left button up" << LL_ENDL; -				//} -				// Because we move the cursor position in the app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_RBUTTONDBLCLK: -		case WM_RBUTTONDOWN: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				if (LLWinImm::isAvailable() && window_imp->mPreeditor) -				{ -					window_imp->interruptLanguageTextInput(); -				} - -				// Because we move the cursor position in the llviewerapp, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_RBUTTONUP: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				// Because we move the cursor position in the app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_MBUTTONDOWN: -//		case WM_MBUTTONDBLCLK: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				if (LLWinImm::isAvailable() && window_imp->mPreeditor) -				{ -					window_imp->interruptLanguageTextInput(); -				} - -				// Because we move the cursor position in tllviewerhe app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_MBUTTONUP: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); -				LLFastTimer t2(FTM_MOUSEHANDLER); -				// Because we move the cursor position in tllviewerhe app, we need to query -				// to find out where the cursor at the time the event is handled. -				// If we don't do this, many clicks could get buffered up, and if the -				// first click changes the cursor position, all subsequent clicks -				// will occur at the wrong location.  JC -				LLCoordWindow cursor_coord_window; -				if (window_imp->mMousePositionModified) -				{ -					window_imp->getCursorPosition(&cursor_coord_window); -					window_imp->convertCoords(cursor_coord_window, &gl_coord); -				} -				else -				{ -					window_imp->convertCoords(window_coord, &gl_coord); -				} -				MASK mask = gKeyboard->currentMask(TRUE); -				// generate move event to update mouse coordinates -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask)) -				{ -					return 0; -				} -			} -			break; - -		case WM_MOUSEWHEEL: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL"); -				static short z_delta = 0; - -				z_delta += HIWORD(w_param); -				// cout << "z_delta " << z_delta << endl; - -				// current mouse wheels report changes in increments of zDelta (+120, -120) -				// Future, higher resolution mouse wheels may report smaller deltas. -				// So we sum the deltas and only act when we've exceeded WHEEL_DELTA -				// -				// If the user rapidly spins the wheel, we can get messages with -				// large deltas, like 480 or so.  Thus we need to scroll more quickly. -				if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) -				{ -					window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA); -					z_delta = 0; -				} -				return 0; -			} -			/* -			// TODO: add this after resolving _WIN32_WINNT issue -			case WM_MOUSELEAVE: -			{ -			window_imp->mCallbacks->handleMouseLeave(window_imp); - -			//				TRACKMOUSEEVENT track_mouse_event; -			//				track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); -			//				track_mouse_event.dwFlags = TME_LEAVE; -			//				track_mouse_event.hwndTrack = h_wnd; -			//				track_mouse_event.dwHoverTime = HOVER_DEFAULT; -			//				TrackMouseEvent( &track_mouse_event );  -			return 0; -			} -			*/ -			// Handle mouse movement within the window -		case WM_MOUSEMOVE: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE"); -				window_imp->convertCoords(window_coord, &gl_coord); -				MASK mask = gKeyboard->currentMask(TRUE); -				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); -				return 0; -			} - -		case WM_SIZE: -			{ -				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE"); -				S32 width = S32( LOWORD(l_param) ); -				S32 height = S32( HIWORD(l_param) ); - -				if (gDebugWindowProc) -				{ -					BOOL maximized = ( w_param == SIZE_MAXIMIZED ); -					BOOL restored  = ( w_param == SIZE_RESTORED ); -					BOOL minimized = ( w_param == SIZE_MINIMIZED ); - -					LL_INFOS("Window") << "WINDOWPROC Size " -						<< width << "x" << height -						<< " max " << S32(maximized) -						<< " min " << S32(minimized) -						<< " rest " << S32(restored) -						<< LL_ENDL; -				} - -				// There's an odd behavior with WM_SIZE that I would call a bug. If  -				// the window is maximized, and you call MoveWindow() with a size smaller -				// than a maximized window, it ends up sending WM_SIZE with w_param set  -				// to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. -				// (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see  -				// LLWindowWin32::moveWindow in this file).  - -				// If we are now restored, but we weren't before, this -				// means that the window was un-minimized. -				if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) -				{ -					window_imp->mCallbacks->handleActivate(window_imp, TRUE); -				} - -				// handle case of window being maximized from fully minimized state -				if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) -				{ -					window_imp->mCallbacks->handleActivate(window_imp, TRUE); -				} - -				// Also handle the minimization case -				if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) -				{ -					window_imp->mCallbacks->handleActivate(window_imp, FALSE); -				} - -				// Actually resize all of our views -				if (w_param != SIZE_MINIMIZED) -				{ -					// Ignore updates for minimizing and minimized "windows" -					window_imp->mCallbacks->handleResize(	window_imp,  -						LOWORD(l_param),  -						HIWORD(l_param) ); -				} - -				window_imp->mLastSizeWParam = w_param; - -				return 0; -			} - -		case WM_SETFOCUS: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); -			if (gDebugWindowProc) -			{ -				LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; -			} -			window_imp->mCallbacks->handleFocus(window_imp); -			return 0; - -		case WM_KILLFOCUS: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS"); -			if (gDebugWindowProc) -			{ -				LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; -			} -			window_imp->mCallbacks->handleFocusLost(window_imp); -			return 0; - -		case WM_COPYDATA: -			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA"); -			// received a URL -			PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param; -			window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData); -			return 0;			 -		} - -	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	 -	} - - -	// pass unhandled messages down to Windows -	return DefWindowProc(h_wnd, u_msg, w_param, l_param); -} - -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ -	S32		client_height; -	RECT	client_rect; -	LLCoordWindow window_position; - -	if (!mWindowHandle || -		!GetClientRect(mWindowHandle, &client_rect) || -		NULL == to) -	{ -		return FALSE; -	} - -	to->mX = from.mX; -	client_height = client_rect.bottom - client_rect.top; -	to->mY = client_height - from.mY - 1; - -	return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ -	S32		client_height; -	RECT	client_rect; - -	if (!mWindowHandle || -		!GetClientRect(mWindowHandle, &client_rect) || -		NULL == to) -	{ -		return FALSE; -	} - -	to->mX = from.mX; -	client_height = client_rect.bottom - client_rect.top; -	to->mY = client_height - from.mY - 1; - -	return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{	 -	POINT mouse_point; - -	mouse_point.x = from.mX; -	mouse_point.y = from.mY; -	BOOL result = ScreenToClient(mWindowHandle, &mouse_point); - -	if (result) -	{ -		to->mX = mouse_point.x; -		to->mY = mouse_point.y; -	} - -	return result; -} - -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ -	POINT mouse_point; - -	mouse_point.x = from.mX; -	mouse_point.y = from.mY; -	BOOL result = ClientToScreen(mWindowHandle, &mouse_point); - -	if (result) -	{ -		to->mX = mouse_point.x; -		to->mY = mouse_point.y; -	} - -	return result; -} - -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ -	LLCoordWindow window_coord; - -	if (!mWindowHandle || (NULL == to)) -	{ -		return FALSE; -	} - -	convertCoords(from, &window_coord); -	convertCoords(window_coord, to); -	return TRUE; -} - -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ -	LLCoordWindow window_coord; - -	if (!mWindowHandle || (NULL == to)) -	{ -		return FALSE; -	} - -	convertCoords(from, &window_coord); -	convertCoords(window_coord, to); -	return TRUE; -} - - -BOOL LLWindowWin32::isClipboardTextAvailable() -{ -	return IsClipboardFormatAvailable(CF_UNICODETEXT); -} - - -BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) -{ -	BOOL success = FALSE; - -	if (IsClipboardFormatAvailable(CF_UNICODETEXT)) -	{ -		if (OpenClipboard(mWindowHandle)) -		{ -			HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); -			if (h_data) -			{ -				WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); -				if (utf16str) -				{ -					dst = utf16str_to_wstring(utf16str); -					LLWStringUtil::removeCRLF(dst); -					GlobalUnlock(h_data); -					success = TRUE; -				} -			} -			CloseClipboard(); -		} -	} - -	return success; -} - - -BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) -{ -	BOOL success = FALSE; - -	if (OpenClipboard(mWindowHandle)) -	{ -		EmptyClipboard(); - -		// Provide a copy of the data in Unicode format. -		LLWString sanitized_string(wstr); -		LLWStringUtil::addCRLF(sanitized_string); -		llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); -		const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); - -		// Memory is allocated and then ownership of it is transfered to the system. -		HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16);  -		if (hglobal_copy_utf16) -		{ -			WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); -			if (copy_utf16) -			{ -				memcpy(copy_utf16, out_utf16.c_str(), size_utf16);	/* Flawfinder: ignore */ -				GlobalUnlock(hglobal_copy_utf16); - -				if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) -				{ -					success = TRUE; -				} -			} -		} - -		CloseClipboard(); -	} - -	return success; -} - -// Constrains the mouse to the window. -void LLWindowWin32::setMouseClipping( BOOL b ) -{ -	if( b != mIsMouseClipping ) -	{ -		BOOL success = FALSE; - -		if( b ) -		{ -			GetClipCursor( &mOldMouseClip ); - -			RECT client_rect_in_screen_space; -			if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) -			{ -				success = ClipCursor( &client_rect_in_screen_space ); -			} -		} -		else -		{ -			// Must restore the old mouse clip, which may be set by another window. -			success = ClipCursor( &mOldMouseClip ); -			SetRect( &mOldMouseClip, 0, 0, 0, 0 ); -		} - -		if( success ) -		{ -			mIsMouseClipping = b; -		} -	} -} - -BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) -{ -	BOOL success = FALSE; - -	RECT client_rect; -	if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) ) -	{ -		POINT top_left; -		top_left.x = client_rect.left; -		top_left.y = client_rect.top; -		ClientToScreen(mWindowHandle, &top_left);  - -		POINT bottom_right; -		bottom_right.x = client_rect.right; -		bottom_right.y = client_rect.bottom; -		ClientToScreen(mWindowHandle, &bottom_right);  - -		SetRect( rectp, -			top_left.x, -			top_left.y, -			bottom_right.x, -			bottom_right.y ); - -		success = TRUE; -	} - -	return success; -} - -void LLWindowWin32::flashIcon(F32 seconds) -{ -	FLASHWINFO flash_info; - -	flash_info.cbSize = sizeof(FLASHWINFO); -	flash_info.hwnd = mWindowHandle; -	flash_info.dwFlags = FLASHW_TRAY; -	flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); -	flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds -	FlashWindowEx(&flash_info); -} - -F32 LLWindowWin32::getGamma() -{ -	return mCurrentGamma; -} - -BOOL LLWindowWin32::restoreGamma() -{ -	return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); -} - -BOOL LLWindowWin32::setGamma(const F32 gamma) -{ -	mCurrentGamma = gamma; - -	LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; - -	for ( int i = 0; i < 256; ++i ) -	{ -		int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); - -		int value = mult * i; - -		if ( value > 0xffff ) -			value = 0xffff; - -		mCurrentGammaRamp [ 0 * 256 + i ] =  -			mCurrentGammaRamp [ 1 * 256 + i ] =  -				mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value; -	}; - -	return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); -} - -void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) -{ -	mFSAASamples = fsaa_samples; -} - -U32 LLWindowWin32::getFSAASamples() -{ -	return mFSAASamples; -} - -LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) -{ -	if (!mSupportedResolutions) -	{ -		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; -		DEVMODE dev_mode; - -		mNumSupportedResolutions = 0; -		for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) -		{ -			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) -			{ -				break; -			} - -			if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && -				dev_mode.dmPelsWidth >= 800 && -				dev_mode.dmPelsHeight >= 600) -			{ -				BOOL resolution_exists = FALSE; -				for(S32 i = 0; i < mNumSupportedResolutions; i++) -				{ -					if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && -						mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) -					{ -						resolution_exists = TRUE; -					} -				} -				if (!resolution_exists) -				{ -					mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; -					mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; -					mNumSupportedResolutions++; -				} -			} -		} -	} - -	num_resolutions = mNumSupportedResolutions; -	return mSupportedResolutions; -} - - -F32 LLWindowWin32::getNativeAspectRatio() -{ -	if (mOverrideAspectRatio > 0.f) -	{ -		return mOverrideAspectRatio; -	} -	else if (mNativeAspectRatio > 0.f) -	{ -		// we grabbed this value at startup, based on the user's desktop settings -		return mNativeAspectRatio; -	} -	// RN: this hack presumes that the largest supported resolution is monitor-limited -	// and that pixels in that mode are square, therefore defining the native aspect ratio -	// of the monitor...this seems to work to a close approximation for most CRTs/LCDs -	S32 num_resolutions; -	LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - -	return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); -} - -F32 LLWindowWin32::getPixelAspectRatio() -{ -	F32 pixel_aspect = 1.f; -	if (getFullscreen()) -	{ -		LLCoordScreen screen_size; -		getSize(&screen_size); -		pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; -	} - -	return pixel_aspect; -} - -// Change display resolution.  Returns true if successful. -// protected -BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) -{ -	DEVMODE dev_mode; -	dev_mode.dmSize = sizeof(dev_mode); -	BOOL success = FALSE; - -	// Don't change anything if we don't have to -	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) -	{ -		if (dev_mode.dmPelsWidth        == width && -			dev_mode.dmPelsHeight       == height && -			dev_mode.dmBitsPerPel       == bits && -			dev_mode.dmDisplayFrequency == refresh ) -		{ -			// ...display mode identical, do nothing -			return TRUE; -		} -	} - -	memset(&dev_mode, 0, sizeof(dev_mode)); -	dev_mode.dmSize = sizeof(dev_mode); -	dev_mode.dmPelsWidth        = width; -	dev_mode.dmPelsHeight       = height; -	dev_mode.dmBitsPerPel       = bits; -	dev_mode.dmDisplayFrequency = refresh; -	dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - -	// CDS_FULLSCREEN indicates that this is a temporary change to the device mode. -	LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); - -	success = (DISP_CHANGE_SUCCESSFUL == cds_result); - -	if (!success) -	{ -		LL_WARNS("Window") << "setDisplayResolution failed, " -			<< width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; -	} - -	return success; -} - -// protected -BOOL LLWindowWin32::setFullscreenResolution() -{ -	if (mFullscreen) -	{ -		return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); -	} -	else -	{ -		return FALSE; -	} -} - -// protected -BOOL LLWindowWin32::resetDisplayResolution() -{ -	LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; - -	LONG cds_result = ChangeDisplaySettings(NULL, 0); - -	BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); - -	if (!success) -	{ -		LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; -	} - -	LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; - -	return success; -} - -void LLWindowWin32::swapBuffers() -{ -	SwapBuffers(mhDC); -} - - -// -// LLSplashScreenImp -// -LLSplashScreenWin32::LLSplashScreenWin32() -:	mWindow(NULL) -{ -} - -LLSplashScreenWin32::~LLSplashScreenWin32() -{ -} - -void LLSplashScreenWin32::showImpl() -{ -	// This appears to work.  ??? -	HINSTANCE hinst = GetModuleHandle(NULL); - -	mWindow = CreateDialog(hinst,  -		TEXT("SPLASHSCREEN"),  -		NULL,	// no parent -		(DLGPROC) LLSplashScreenWin32::windowProc);  -	ShowWindow(mWindow, SW_SHOW); -} - - -void LLSplashScreenWin32::updateImpl(const std::string& mesg) -{ -	if (!mWindow) return; - -	WCHAR w_mesg[1024]; -	mbstowcs(w_mesg, mesg.c_str(), 1024); - -	SendDlgItemMessage(mWindow, -		666,		// HACK: text id -		WM_SETTEXT, -		FALSE, -		(LPARAM)w_mesg); -} - - -void LLSplashScreenWin32::hideImpl() -{ -	if (mWindow) -	{ -		DestroyWindow(mWindow); -		mWindow = NULL;  -	} -} - - -// static -LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, -											WPARAM w_param, LPARAM l_param) -{ -	// Just give it to windows -	return DefWindowProc(h_wnd, u_msg, w_param, l_param); -} - -// -// Helper Funcs -// - -S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) -{ -	UINT uType; - -	switch(type) -	{ -	case OSMB_OK: -		uType = MB_OK; -		break; -	case OSMB_OKCANCEL: -		uType = MB_OKCANCEL; -		break; -	case OSMB_YESNO: -		uType = MB_YESNO; -		break; -	default: -		uType = MB_OK; -		break; -	} - -	// HACK! Doesn't properly handle wide strings! -	int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType); -	S32 retval; - -	switch(retval_win) -	{ -	case IDYES: -		retval = OSBTN_YES; -		break; -	case IDNO: -		retval = OSBTN_NO; -		break; -	case IDOK: -		retval = OSBTN_OK; -		break; -	case IDCANCEL: -		retval = OSBTN_CANCEL; -		break; -	default: -		retval = OSBTN_CANCEL; -		break; -	} - -	return retval; -} - - -void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url ) -{ -	bool found = false; -	S32 i; -	for (i = 0; i < gURLProtocolWhitelistCount; i++) -	{ -		if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) -		{ -			found = true; -			break; -		} -	} - -	if (!found) -	{ -		LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; -		return; -	} - -	LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - -	// replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work -	// reliablly on Vista. - -	// this is madness.. no, this is.. -	LLWString url_wstring = utf8str_to_wstring( escaped_url ); -	llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - -	// let the OS decide what to use to open the URL -	SHELLEXECUTEINFO sei = { sizeof( sei ) }; -	sei.fMask = SEE_MASK_FLAG_DDEWAIT; -	sei.nShow = SW_SHOWNORMAL; -	sei.lpVerb = L"open"; -	sei.lpFile = url_utf16.c_str(); -	ShellExecuteEx( &sei ); - -	//// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES -	//// DELETE THIS ONCE THE MERGES ARE DONE - -	// Figure out the user's default web browser -	// HKEY_CLASSES_ROOT\http\shell\open\command -	/* -	std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\\shell\\open\\command"; -	WCHAR reg_path_wstr[256]; -	mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) ); - -	HKEY key; -	WCHAR browser_open_wstr[1024]; -	DWORD buffer_length = 1024; -	RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key); -	RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length); -	RegCloseKey(key); - -	// Convert to STL string -	LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr); - -	if (browser_open_wstring.length() < 2) -	{ -		LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL; -		return; -	} - -	// Extract the process that's supposed to be launched -	LLWString browser_executable; -	if (browser_open_wstring[0] == '"') -	{ -		// executable is quoted, find the matching quote -		size_t quote_pos = browser_open_wstring.find('"', 1); -		// copy out the string including both quotes -		browser_executable = browser_open_wstring.substr(0, quote_pos+1); -	} -	else -	{ -		// executable not quoted, find a space -		size_t space_pos = browser_open_wstring.find(' ', 1); -		browser_executable = browser_open_wstring.substr(0, space_pos); -	} - -	LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL; -	LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL; - -	// Convert URL to wide string for Windows API -	// Assume URL is UTF8, as can come from scripts -	LLWString url_wstring = utf8str_to_wstring(escaped_url); -	llutf16string url_utf16 = wstring_to_utf16str(url_wstring); - -	// Convert executable and path to wide string for Windows API -	llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable); - -	// ShellExecute returns HINSTANCE for backwards compatiblity. -	// MS docs say to cast to int and compare to 32. -	HWND our_window = NULL; -	LPCWSTR directory_wstr = NULL; -	int retval = (int) ShellExecute(our_window, 	// Flawfinder: ignore -									L"open",  -									browser_exec_utf16.c_str(),  -									url_utf16.c_str(),  -									directory_wstr, -									SW_SHOWNORMAL); -	if (retval > 32) -	{ -		LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL; -	} -	else -	{ -		LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL; -	} -	*/ -} - - -BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) -{ -	BOOL retval = FALSE; - -	static CHOOSECOLOR cc; -	static COLORREF crCustColors[16]; -	cc.lStructSize = sizeof(CHOOSECOLOR); -	cc.hwndOwner = mWindowHandle; -	cc.hInstance = NULL; -	cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); -	//cc.rgbResult = RGB (0x80,0x80,0x80);  -	cc.lpCustColors = crCustColors; -	cc.Flags = CC_RGBINIT | CC_FULLOPEN; -	cc.lCustData = 0; -	cc.lpfnHook = NULL; -	cc.lpTemplateName = NULL; -  -	// This call is modal, so pause agent -	//send_agent_pause();	// this is in newview and we don't want to set up a dependency -	{ -		retval = ChooseColor(&cc); -	} -	//send_agent_resume();	// this is in newview and we don't want to set up a dependency - -	*b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; - -	*g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; -	 -	*r = ((F32)(cc.rgbResult & 0xff)) / 255.f; - -	return (retval); -} - -void *LLWindowWin32::getPlatformWindow() -{ -	return (void*)mWindowHandle; -} - -void LLWindowWin32::bringToFront() -{ -	BringWindowToTop(mWindowHandle); -} - -// set (OS) window focus back to the client -void LLWindowWin32::focusClient() -{ -	SetFocus ( mWindowHandle ); -} - -void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) -{ -	if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) -	{ -		return; -	} - -	if (preeditor != mPreeditor && !b) -	{ -		// This condition may occur with a call to -		// setEnabled(BOOL) from LLTextEditor or LLLineEditor -		// when the control is not focused. -		// We need to silently ignore the case so that -		// the language input status of the focused control -		// is not disturbed. -		return; -	} - -	// Take care of old and new preeditors. -	if (preeditor != mPreeditor || !b) -	{ -		if (sLanguageTextInputAllowed) -		{ -			interruptLanguageTextInput(); -		} -		mPreeditor = (b ? preeditor : NULL); -	} - -	sLanguageTextInputAllowed = b; - -	if ( sLanguageTextInputAllowed ) -	{ -		// Allowing: Restore the previous IME status, so that the user has a feeling that the previous  -		// text input continues naturally.  Be careful, however, the IME status is meaningful only during the user keeps  -		// using same Input Locale (aka Keyboard Layout). -		if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) -		{ -			HIMC himc = LLWinImm::getContext(mWindowHandle); -			LLWinImm::setOpenStatus(himc, TRUE); -			LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); -			LLWinImm::releaseContext(mWindowHandle, himc); -		} -	} -	else -	{ -		// Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. -		// However, do it after saving the current IME  status.  We need to restore the status when -		//   allowing language text input again. -		sWinInputLocale = GetKeyboardLayout(0); -		sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); -		if (sWinIMEOpened) -		{ -			HIMC himc = LLWinImm::getContext(mWindowHandle); -			sWinIMEOpened = LLWinImm::getOpenStatus(himc); -			if (sWinIMEOpened) -			{ -				LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); - -				// We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's  -				// keyboard hooking, because Some IME reacts only on the former and some other on the latter... -				LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); -				LLWinImm::setOpenStatus(himc, FALSE); -			} -			LLWinImm::releaseContext(mWindowHandle, himc); - 		} -	} -} - -void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds,  -		CANDIDATEFORM *form) -{ -	LLCoordWindow caret_coord, top_left, bottom_right; -	convertCoords(caret, &caret_coord); -	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); -	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - -	memset(form, 0, sizeof(CANDIDATEFORM)); -	form->dwStyle = CFS_EXCLUDE; -	form->ptCurrentPos.x = caret_coord.mX; -	form->ptCurrentPos.y = caret_coord.mY; -	form->rcArea.left   = top_left.mX; -	form->rcArea.top    = top_left.mY; -	form->rcArea.right  = bottom_right.mX; -	form->rcArea.bottom = bottom_right.mY; -} - - -// Put the IME window at the right place (near current text input).   Point coordinates should be the top of the current text line. -void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) -{ -	if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) -	{ -		HIMC himc = LLWinImm::getContext(mWindowHandle); - -		LLCoordWindow win_pos; -		convertCoords( position, &win_pos ); - -		if ( win_pos.mX >= 0 && win_pos.mY >= 0 &&  -			(win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) -		{ -			COMPOSITIONFORM ime_form; -			memset( &ime_form, 0, sizeof(ime_form) ); -			ime_form.dwStyle = CFS_POINT; -			ime_form.ptCurrentPos.x = win_pos.mX; -			ime_form.ptCurrentPos.y = win_pos.mY; - -			LLWinImm::setCompositionWindow( himc, &ime_form ); - -			sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY ); -		} - -		LLWinImm::releaseContext(mWindowHandle, himc); -	} -} - - -void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, -		IMECHARPOSITION *char_position) -{ -	LLCoordScreen caret_coord, top_left, bottom_right; -	convertCoords(caret, &caret_coord); -	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); -	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - -	char_position->pt.x = caret_coord.mX; -	char_position->pt.y = top_left.mY;	// Windows wants the coordinate of upper left corner of a character... -	char_position->cLineHeight = bottom_right.mY - top_left.mY; -	char_position->rcDocument.left   = top_left.mX; -	char_position->rcDocument.top    = top_left.mY; -	char_position->rcDocument.right  = bottom_right.mX; -	char_position->rcDocument.bottom = bottom_right.mY; -} - -void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) -{ -	// Our font is a list of FreeType recognized font files that may -	// not have a corresponding ones in Windows' fonts.  Hence, we -	// can't simply tell Windows which font we are using.  We will -	// notify a _standard_ font for a current input locale instead. -	// We use a hard-coded knowledge about the Windows' standard -	// configuration to do so... - -	memset(logfont, 0, sizeof(LOGFONT)); - -	const WORD lang_id = LOWORD(GetKeyboardLayout(0)); -	switch (PRIMARYLANGID(lang_id)) -	{ -	case LANG_CHINESE: -		// We need to identify one of two Chinese fonts. -		switch (SUBLANGID(lang_id)) -		{ -		case SUBLANG_CHINESE_SIMPLIFIED: -		case SUBLANG_CHINESE_SINGAPORE: -			logfont->lfCharSet = GB2312_CHARSET; -			lstrcpy(logfont->lfFaceName, TEXT("SimHei")); -			break; -		case SUBLANG_CHINESE_TRADITIONAL: -		case SUBLANG_CHINESE_HONGKONG: -		case SUBLANG_CHINESE_MACAU: -		default: -			logfont->lfCharSet = CHINESEBIG5_CHARSET; -			lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); -			break;			 -		} -		break; -	case LANG_JAPANESE: -		logfont->lfCharSet = SHIFTJIS_CHARSET; -		lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); -		break;		 -	case LANG_KOREAN: -		logfont->lfCharSet = HANGUL_CHARSET; -		lstrcpy(logfont->lfFaceName, TEXT("Gulim")); -		break; -	default: -		logfont->lfCharSet = ANSI_CHARSET; -		lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); -		break; -	} -							 -	logfont->lfHeight = mPreeditor->getPreeditFontSize(); -	logfont->lfWeight = FW_NORMAL; -}	 - -U32 LLWindowWin32::fillReconvertString(const LLWString &text, -	S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) -{ -	const llutf16string text_utf16 = wstring_to_utf16str(text); -	const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); -	if (reconvert_string && reconvert_string->dwSize >= required_size) -	{ -		const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); -		const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); - -		reconvert_string->dwVersion = 0; -		reconvert_string->dwStrLen = text_utf16.length(); -		reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); -		reconvert_string->dwCompStrLen = focus_utf16_length; -		reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); -		reconvert_string->dwTargetStrLen = 0; -		reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); - -		const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); -		memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); -	} -	return required_size; -} - -void LLWindowWin32::updateLanguageTextInputArea() -{ -	if (!mPreeditor || !LLWinImm::isAvailable()) -	{ -		return; -	} - -	LLCoordGL caret_coord; -	LLRect preedit_bounds; -	if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) -	{ -		mLanguageTextInputPointGL = caret_coord; -		mLanguageTextInputAreaGL = preedit_bounds; - -		CANDIDATEFORM candidate_form; -		fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); - -		HIMC himc = LLWinImm::getContext(mWindowHandle); -		// Win32 document says there may be up to 4 candidate windows. -		// This magic number 4 appears only in the document, and -		// there are no constant/macro for the value... -		for (int i = 3; i >= 0; --i) -		{ -			candidate_form.dwIndex = i; -			LLWinImm::setCandidateWindow(himc, &candidate_form); -		} -		LLWinImm::releaseContext(mWindowHandle, himc); -	} -} - -void LLWindowWin32::interruptLanguageTextInput() -{ -	if (mPreeditor) -	{ -		if (LLWinImm::isAvailable()) -		{ -			HIMC himc = LLWinImm::getContext(mWindowHandle); -			LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); -			LLWinImm::releaseContext(mWindowHandle, himc); -		} - -		// Win32 document says there will be no composition string -		// after NI_COMPOSITIONSTR returns.  The following call to -		// resetPreedit should be a NOP unless IME goes mad... -		mPreeditor->resetPreedit(); -	} -} - -void LLWindowWin32::handleStartCompositionMessage() -{ -	// Let IME know the font to use in feedback UI. -	LOGFONT logfont; -	fillCompositionLogfont(&logfont); -	HIMC himc = LLWinImm::getContext(mWindowHandle); -	LLWinImm::setCompositionFont(himc, &logfont); -	LLWinImm::releaseContext(mWindowHandle, himc); -} - -// Handle WM_IME_COMPOSITION message. - -void LLWindowWin32::handleCompositionMessage(const U32 indexes) -{ -	BOOL needs_update = FALSE; -	LLWString result_string; -	LLWString preedit_string; -	S32 preedit_string_utf16_length = 0; -	LLPreeditor::segment_lengths_t preedit_segment_lengths; -	LLPreeditor::standouts_t preedit_standouts; - -	// Step I: Receive details of preedits from IME. - -	HIMC himc = LLWinImm::getContext(mWindowHandle); - -	if (indexes & GCS_RESULTSTR) -	{ -		LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); -		if (size >= 0) -		{ -			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; -			size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); -			if (size > 0) -			{ -				result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); -			} -			delete[] data; -			needs_update = TRUE; -		} -	} -	 -	if (indexes & GCS_COMPSTR) -	{ -		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); -		if (size >= 0) -		{ -			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; -			size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); -			if (size > 0) -			{ -				preedit_string_utf16_length = size / sizeof(WCHAR); -				preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); -			} -			delete[] data; -			needs_update = TRUE; -		} -	} - -	if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) -	{ -		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); -		if (size > 0) -		{ -			const LPDWORD data = new DWORD[size / sizeof(DWORD)]; -			size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); -			if (size >= sizeof(DWORD) * 2 -				&& data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) -			{ -				preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); -				S32 offset = 0; -				for (U32 i = 0; i < preedit_segment_lengths.size(); i++) -				{ -					const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); -					preedit_segment_lengths[i] = length; -					offset += length; -				} -			} -			delete[] data; -		} -	} - -	if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) -	{ -		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); -		if (size > 0) -		{ -			const LPBYTE data = new BYTE[size / sizeof(BYTE)]; -			size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); -			if (size == preedit_string_utf16_length) -			{ -				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); -				S32 offset = 0; -				for (U32 i = 0; i < preedit_segment_lengths.size(); i++) -				{ -					if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) -					{ -						preedit_standouts[i] = TRUE; -					} -					offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); -				} -			} -			delete[] data; -		} -	} - -	S32 caret_position = preedit_string.length(); -	if (indexes & GCS_CURSORPOS) -	{ -		const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); -		if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) -		{ -			caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); -		} -	} - -	if (indexes == 0) -	{ -		// I'm not sure this condition really happens, but -		// Windows SDK document says it is an indication -		// of "reset everything." -		needs_update = TRUE; -	} - -	LLWinImm::releaseContext(mWindowHandle, himc); - -	// Step II: Update the active preeditor. - -	if (needs_update) -	{ -		mPreeditor->resetPreedit(); - -		if (result_string.length() > 0) -		{ -			for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) -			{ -				mPreeditor->handleUnicodeCharHere(*i); -			} -		} - -		if (preedit_string.length() == 0) - 		{ -			preedit_segment_lengths.clear(); -			preedit_standouts.clear(); -		} -		else -		{ -			if (preedit_segment_lengths.size() == 0) -			{ -				preedit_segment_lengths.assign(1, preedit_string.length()); -			} -			if (preedit_standouts.size() == 0) -			{ -				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); -			} -		} -		mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - -		// Some IME doesn't query char position after WM_IME_COMPOSITION, -		// so we need to update them actively. -		updateLanguageTextInputArea(); -	} -} - -// Given a text and a focus range, find_context finds and returns a -// surrounding context of the focused subtext.  A variable pointed -// to by offset receives the offset in llwchars of the beginning of -// the returned context string in the given wtext. - -static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) -{ -	static const S32 CONTEXT_EXCESS = 30;	// This value is by experiences. - -	const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); -	S32 end = focus + focus_length; -	while (end < e && '\n' != wtext[end]) -	{ -		end++; -	} - -	const S32 s = llmax(0, focus - CONTEXT_EXCESS); -	S32 start = focus; -	while (start > s && '\n' != wtext[start - 1]) -	{ -		--start; -	} - -	*offset = start; -	return wtext.substr(start, end - start); -} - -// Handle WM_IME_REQUEST message. -// If it handled the message, returns TRUE.  Otherwise, FALSE. -// When it handled the message, the value to be returned from -// the Window Procedure is set to *result. - -BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result) -{ -	if ( mPreeditor ) -	{ -		switch (request) -		{ -			case IMR_CANDIDATEWINDOW:		// http://msdn2.microsoft.com/en-us/library/ms776080.aspx -			{ -				LLCoordGL caret_coord; -				LLRect preedit_bounds; -				mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); -				 -				CANDIDATEFORM *const form = (CANDIDATEFORM *)param; -				DWORD const dwIndex = form->dwIndex; -				fillCandidateForm(caret_coord, preedit_bounds, form); -				form->dwIndex = dwIndex; - -				*result = 1; -				return TRUE; -			} -			case IMR_QUERYCHARPOSITION: -			{ -				IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; - -				// char_position->dwCharPos counts in number of -				// WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the -				// number to getPreeditLocation.   - -				const LLWString & wtext = mPreeditor->getPreeditString(); -				S32 preedit, preedit_length; -				mPreeditor->getPreeditRange(&preedit, &preedit_length); -				LLCoordGL caret_coord; -				LLRect preedit_bounds, text_control; -				const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); - -				if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) -				{ -					LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; -					return FALSE; -				} -				fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); - -				*result = 1; -				return TRUE; -			} -			case IMR_COMPOSITIONFONT: -			{ -				fillCompositionLogfont((LOGFONT *)param); - -				*result = 1; -				return TRUE; -			} -			case IMR_RECONVERTSTRING: -			{ -				mPreeditor->resetPreedit(); -				const LLWString & wtext = mPreeditor->getPreeditString(); -				S32 select, select_length; -				mPreeditor->getSelectionRange(&select, &select_length); - -				S32 context_offset; -				const LLWString context = find_context(wtext, select, select_length, &context_offset); - -				RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; -				const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); -				if (reconvert_string) -				{ -					if (select_length == 0) -					{ -						// Let the IME to decide the reconversion range, and -						// adjust the reconvert_string structure accordingly. -						HIMC himc = LLWinImm::getContext(mWindowHandle); -						const BOOL adjusted = LLWinImm::setCompositionString(himc, -									SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); -						LLWinImm::releaseContext(mWindowHandle, himc); -						if (adjusted) -						{ -							const llutf16string & text_utf16 = wstring_to_utf16str(context); -							const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); -							const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; -							select = utf16str_wstring_length(text_utf16, new_preedit_start); -							select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; -							select += context_offset; -						} -					} -					mPreeditor->markAsPreedit(select, select_length); -				} - -				*result = size; -				return TRUE; -			} -			case IMR_CONFIRMRECONVERTSTRING: -			{ -				*result = FALSE; -				return TRUE; -			} -			case IMR_DOCUMENTFEED: -			{ -				const LLWString & wtext = mPreeditor->getPreeditString(); -				S32 preedit, preedit_length; -				mPreeditor->getPreeditRange(&preedit, &preedit_length); -				 -				S32 context_offset; -				LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); -				preedit -= context_offset; -				if (preedit_length) -				{ -					// IMR_DOCUMENTFEED may be called when we have an active preedit. -					// We should pass the context string *excluding* the preedit string. -					// Otherwise, some IME are confused. -					context.erase(preedit, preedit_length); -				} -				 -				RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; -				*result = fillReconvertString(context, preedit, 0, reconvert_string); -				return TRUE; -			} -			default: -				return FALSE; -		} -	} - -	return FALSE; -} - -//static -std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() -{ -	// Fonts previously in getFontListSans() have moved to fonts.xml. -	return std::vector<std::string>(); -} - - -#endif // LL_WINDOWS +/** 
 + * @file llwindowwin32.cpp
 + * @brief Platform-dependent implementation of llwindow
 + *
 + * $LicenseInfo:firstyear=2001&license=viewergpl$
 + * 
 + * Copyright (c) 2001-2009, 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 "linden_common.h"
 +
 +#if LL_WINDOWS && !LL_MESA_HEADLESS
 +
 +#include "llwindowwin32.h"
 +
 +// LLWindow library includes
 +#include "llkeyboardwin32.h"
 +#include "lldragdropwin32.h"
 +#include "llpreeditor.h"
 +#include "llwindowcallbacks.h"
 +
 +// Linden library includes
 +#include "llerror.h"
 +#include "llgl.h"
 +#include "llstring.h"
 +
 +// System includes
 +#include <commdlg.h>
 +#include <WinUser.h>
 +#include <mapi.h>
 +#include <process.h>	// for _spawn
 +#include <shellapi.h>
 +#include <fstream>
 +#include <Imm.h>
 +
 +// Require DirectInput version 8
 +#define DIRECTINPUT_VERSION 0x0800
 +
 +#include <dinput.h>
 +#include <Dbt.h.>
 +
 +#include "llmemtype.h"
 +// culled from winuser.h
 +#ifndef WM_MOUSEWHEEL /* Added to be compatible with later SDK's */
 +const S32	WM_MOUSEWHEEL = 0x020A;
 +#endif
 +#ifndef WHEEL_DELTA /* Added to be compatible with later SDK's */
 +const S32	WHEEL_DELTA = 120;     /* Value for rolling one detent */
 +#endif
 +const S32	MAX_MESSAGE_PER_UPDATE = 20;
 +const S32	BITS_PER_PIXEL = 32;
 +const S32	MAX_NUM_RESOLUTIONS = 32;
 +const F32	ICON_FLASH_TIME = 0.5f;
 +
 +extern BOOL gDebugWindowProc;
 +
 +LPWSTR gIconResource = IDI_APPLICATION;
 +
 +LLW32MsgCallback gAsyncMsgCallback = NULL;
 +
 +//
 +// LLWindowWin32
 +//
 +
 +void show_window_creation_error(const std::string& title)
 +{
 +	LL_WARNS("Window") << title << LL_ENDL;
 +}
 +
 +//static
 +BOOL LLWindowWin32::sIsClassRegistered = FALSE;
 +
 +BOOL	LLWindowWin32::sLanguageTextInputAllowed = TRUE;
 +BOOL	LLWindowWin32::sWinIMEOpened = FALSE;
 +HKL		LLWindowWin32::sWinInputLocale = 0;
 +DWORD	LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE;
 +DWORD	LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC;
 +LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1);
 +
 +// The following class LLWinImm delegates Windows IMM APIs.
 +// We need this because some language versions of Windows,
 +// e.g., US version of Windows XP, doesn't install IMM32.DLL
 +// as a default, and we can't link against imm32.lib statically.
 +// I believe DLL loading of this type is best suited to do
 +// in a static initialization of a class.  What I'm not sure is
 +// whether it follows the Linden Conding Standard... 
 +// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members
 +
 +class LLWinImm
 +{
 +public:
 +	static bool		isAvailable() { return sTheInstance.mHImmDll != NULL; }
 +
 +public:
 +	// Wrappers for IMM API.
 +	static BOOL		isIME(HKL hkl);															
 +	static HWND		getDefaultIMEWnd(HWND hwnd);
 +	static HIMC		getContext(HWND hwnd);													
 +	static BOOL		releaseContext(HWND hwnd, HIMC himc);
 +	static BOOL		getOpenStatus(HIMC himc);												
 +	static BOOL		setOpenStatus(HIMC himc, BOOL status);									
 +	static BOOL		getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence);	
 +	static BOOL		setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence);		
 +	static BOOL		getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					
 +	static BOOL		setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form);					
 +	static LONG		getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length);
 +	static BOOL		setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength);
 +	static BOOL		setCompositionFont(HIMC himc, LPLOGFONTW logfont);
 +	static BOOL		setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form);
 +	static BOOL		notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value);
 +
 +private:
 +	LLWinImm();
 +	~LLWinImm();
 +
 +private:
 +	// Pointers to IMM API.
 +	BOOL	 	(WINAPI *mImmIsIME)(HKL);
 +	HWND		(WINAPI *mImmGetDefaultIMEWnd)(HWND);
 +	HIMC		(WINAPI *mImmGetContext)(HWND);
 +	BOOL		(WINAPI *mImmReleaseContext)(HWND, HIMC);
 +	BOOL		(WINAPI *mImmGetOpenStatus)(HIMC);
 +	BOOL		(WINAPI *mImmSetOpenStatus)(HIMC, BOOL);
 +	BOOL		(WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
 +	BOOL		(WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD);
 +	BOOL		(WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
 +	BOOL		(WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM);
 +	LONG		(WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD);
 +	BOOL		(WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD);
 +	BOOL		(WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW);
 +	BOOL		(WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM);
 +	BOOL		(WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD);
 +
 +private:
 +	HMODULE		mHImmDll;
 +	static LLWinImm sTheInstance;
 +};
 +
 +LLWinImm LLWinImm::sTheInstance;
 +
 +LLWinImm::LLWinImm() : mHImmDll(NULL)
 +{
 +	// Check system metrics 
 +	if ( !GetSystemMetrics( SM_DBCSENABLED ) )
 +		return;
 +	
 +
 +	mHImmDll = LoadLibraryA("Imm32");
 +	if (mHImmDll != NULL)
 +	{
 +		mImmIsIME               = (BOOL (WINAPI *)(HKL))                    GetProcAddress(mHImmDll, "ImmIsIME");
 +		mImmGetDefaultIMEWnd	= (HWND (WINAPI *)(HWND))					GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd");
 +		mImmGetContext          = (HIMC (WINAPI *)(HWND))                   GetProcAddress(mHImmDll, "ImmGetContext");
 +		mImmReleaseContext      = (BOOL (WINAPI *)(HWND, HIMC))             GetProcAddress(mHImmDll, "ImmReleaseContext");
 +		mImmGetOpenStatus       = (BOOL (WINAPI *)(HIMC))                   GetProcAddress(mHImmDll, "ImmGetOpenStatus");
 +		mImmSetOpenStatus       = (BOOL (WINAPI *)(HIMC, BOOL))             GetProcAddress(mHImmDll, "ImmSetOpenStatus");
 +		mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus");
 +		mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD))     GetProcAddress(mHImmDll, "ImmSetConversionStatus");
 +		mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmGetCompositionWindow");
 +		mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM))   GetProcAddress(mHImmDll, "ImmSetCompositionWindow");
 +		mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD))					GetProcAddress(mHImmDll, "ImmGetCompositionStringW");
 +		mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD))	GetProcAddress(mHImmDll, "ImmSetCompositionStringW");
 +		mImmSetCompositionFont  = (BOOL (WINAPI *)(HIMC, LPLOGFONTW))		GetProcAddress(mHImmDll, "ImmSetCompositionFontW");
 +		mImmSetCandidateWindow  = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM))  GetProcAddress(mHImmDll, "ImmSetCandidateWindow");
 +		mImmNotifyIME			= (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD))	GetProcAddress(mHImmDll, "ImmNotifyIME");
 +
 +		if (mImmIsIME == NULL ||
 +			mImmGetDefaultIMEWnd == NULL ||
 +			mImmGetContext == NULL ||
 +			mImmReleaseContext == NULL ||
 +			mImmGetOpenStatus == NULL ||
 +			mImmSetOpenStatus == NULL ||
 +			mImmGetConversionStatus == NULL ||
 +			mImmSetConversionStatus == NULL ||
 +			mImmGetCompostitionWindow == NULL ||
 +			mImmSetCompostitionWindow == NULL ||
 +			mImmGetCompositionString == NULL ||
 +			mImmSetCompositionString == NULL ||
 +			mImmSetCompositionFont == NULL ||
 +			mImmSetCandidateWindow == NULL ||
 +			mImmNotifyIME == NULL)
 +		{
 +			// If any of the above API entires are not found, we can't use IMM API.  
 +			// So, turn off the IMM support.  We should log some warning message in 
 +			// the case, since it is very unusual; these APIs are available from 
 +			// the beginning, and all versions of IMM32.DLL should have them all.  
 +			// Unfortunately, this code may be executed before initialization of 
 +			// the logging channel (llwarns), and we can't do it here...  Yes, this 
 +			// is one of disadvantages to use static constraction to DLL loading. 
 +			FreeLibrary(mHImmDll);
 +			mHImmDll = NULL;
 +
 +			// If we unload the library, make sure all the function pointers are cleared
 +			mImmIsIME = NULL;
 +			mImmGetDefaultIMEWnd = NULL;
 +			mImmGetContext = NULL;
 +			mImmReleaseContext = NULL;
 +			mImmGetOpenStatus = NULL;
 +			mImmSetOpenStatus = NULL;
 +			mImmGetConversionStatus = NULL;
 +			mImmSetConversionStatus = NULL;
 +			mImmGetCompostitionWindow = NULL;
 +			mImmSetCompostitionWindow = NULL;
 +			mImmGetCompositionString = NULL;
 +			mImmSetCompositionString = NULL;
 +			mImmSetCompositionFont = NULL;
 +			mImmSetCandidateWindow = NULL;
 +			mImmNotifyIME = NULL;
 +		}
 +	}
 +}
 +
 +
 +// static 
 +BOOL	LLWinImm::isIME(HKL hkl)															
 +{ 
 +	if ( sTheInstance.mImmIsIME )
 +		return sTheInstance.mImmIsIME(hkl); 
 +	return FALSE;
 +}
 +
 +// static 
 +HIMC		LLWinImm::getContext(HWND hwnd)
 +{
 +	if ( sTheInstance.mImmGetContext )
 +		return sTheInstance.mImmGetContext(hwnd); 
 +	return 0;
 +}
 +
 +//static 
 +BOOL		LLWinImm::releaseContext(HWND hwnd, HIMC himc)
 +{ 
 +	if ( sTheInstance.mImmIsIME )
 +		return sTheInstance.mImmReleaseContext(hwnd, himc); 
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::getOpenStatus(HIMC himc)
 +{ 
 +	if ( sTheInstance.mImmGetOpenStatus )
 +		return sTheInstance.mImmGetOpenStatus(himc); 
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::setOpenStatus(HIMC himc, BOOL status)									
 +{ 
 +	if ( sTheInstance.mImmSetOpenStatus )
 +		return sTheInstance.mImmSetOpenStatus(himc, status); 
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence)	
 +{ 
 +	if ( sTheInstance.mImmGetConversionStatus )
 +		return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); 
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence)		
 +{ 
 +	if ( sTheInstance.mImmSetConversionStatus )
 +		return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); 
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 +{ 
 +	if ( sTheInstance.mImmGetCompostitionWindow )
 +		return sTheInstance.mImmGetCompostitionWindow(himc, form);	
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form)					
 +{ 
 +	if ( sTheInstance.mImmSetCompostitionWindow )
 +		return sTheInstance.mImmSetCompostitionWindow(himc, form);	
 +	return FALSE;
 +}
 +
 +
 +// static 
 +LONG		LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length)					
 +{ 
 +	if ( sTheInstance.mImmGetCompositionString )
 +		return sTheInstance.mImmGetCompositionString(himc, index, data, length);	
 +	return FALSE;
 +}
 +
 +
 +// static 
 +BOOL		LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength)					
 +{ 
 +	if ( sTheInstance.mImmSetCompositionString )
 +		return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength);	
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont)					
 +{ 
 +	if ( sTheInstance.mImmSetCompositionFont )
 +		return sTheInstance.mImmSetCompositionFont(himc, pFont);	
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form)					
 +{ 
 +	if ( sTheInstance.mImmSetCandidateWindow )
 +		return sTheInstance.mImmSetCandidateWindow(himc, form);	
 +	return FALSE;
 +}
 +
 +// static 
 +BOOL		LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value)					
 +{ 
 +	if ( sTheInstance.mImmNotifyIME )
 +		return sTheInstance.mImmNotifyIME(himc, action, index, value);	
 +	return FALSE;
 +}
 +
 +
 +
 +
 +// ----------------------------------------------------------------------------------------
 +LLWinImm::~LLWinImm()
 +{
 +	if (mHImmDll != NULL)
 +	{
 +		FreeLibrary(mHImmDll);
 +		mHImmDll = NULL;
 +	}
 +}
 +
 +
 +LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 +							 const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
 +							 S32 height, U32 flags, 
 +							 BOOL fullscreen, BOOL clearBg,
 +							 BOOL disable_vsync, BOOL use_gl,
 +							 BOOL ignore_pixel_depth,
 +							 U32 fsaa_samples)
 +	: LLWindow(callbacks, fullscreen, flags)
 +{
 +	mFSAASamples = fsaa_samples;
 +	mIconResource = gIconResource;
 +	mOverrideAspectRatio = 0.f;
 +	mNativeAspectRatio = 0.f;
 +	mMousePositionModified = FALSE;
 +	mInputProcessingPaused = FALSE;
 +	mPreeditor = NULL;
 +	mhDC = NULL;
 +	mhRC = NULL;
 +
 +	// Initialize the keyboard
 +	gKeyboard = new LLKeyboardWin32();
 +	gKeyboard->setCallbacks(callbacks);
 +
 +	// Initialize the Drag and Drop functionality
 +	mDragDrop = new LLDragDropWin32;
 +
 +	// Initialize (boot strap) the Language text input management,
 +	// based on the system's (user's) default settings.
 +	allowLanguageTextInput(mPreeditor, FALSE);
 +
 +	WNDCLASS		wc;
 +	RECT			window_rect;
 +
 +	// Set the window title
 +	if (title.empty())
 +	{
 +		mWindowTitle = new WCHAR[50];
 +		wsprintf(mWindowTitle, L"OpenGL Window");
 +	}
 +	else
 +	{
 +		mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars.
 +		mbstowcs(mWindowTitle, title.c_str(), 255);
 +		mWindowTitle[255] = 0;
 +	}
 +
 +	// Set the window class name
 +	if (name.empty())
 +	{
 +		mWindowClassName = new WCHAR[50];
 +		wsprintf(mWindowClassName, L"OpenGL Window");
 +	}
 +	else
 +	{
 +		mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars.
 +		mbstowcs(mWindowClassName, name.c_str(), 255);
 +		mWindowClassName[255] = 0;
 +	}
 +
 +
 +	// We're not clipping yet
 +	SetRect( &mOldMouseClip, 0, 0, 0, 0 );
 +
 +	// Make an instance of our window then define the window class
 +	mhInstance = GetModuleHandle(NULL);
 +	mWndProc = NULL;
 +
 +	mSwapMethod = SWAP_METHOD_UNDEFINED;
 +
 +	// No WPARAM yet.
 +	mLastSizeWParam = 0;
 +
 +	// Windows GDI rects don't include rightmost pixel
 +	window_rect.left = (long) 0;
 +	window_rect.right = (long) width;
 +	window_rect.top = (long) 0;
 +	window_rect.bottom = (long) height;
 +
 +	// Grab screen size to sanitize the window
 +	S32 window_border_y = GetSystemMetrics(SM_CYBORDER);
 +	S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); 
 +	S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); 
 +	S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
 +	S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
 +
 +	if (x < virtual_screen_x) x = virtual_screen_x;
 +	if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y;
 +
 +	if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width;
 +	if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height;
 +
 +	if (!sIsClassRegistered)
 +	{
 +		// Force redraw when resized and create a private device context
 +
 +		// Makes double click messages.
 +		wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
 +
 +		// Set message handler function
 +		wc.lpfnWndProc = (WNDPROC) mainWindowProc;
 +
 +		// unused
 +		wc.cbClsExtra = 0;
 +		wc.cbWndExtra = 0;
 +
 +		wc.hInstance = mhInstance;
 +		wc.hIcon = LoadIcon(mhInstance, mIconResource);
 +
 +		// We will set the cursor ourselves
 +		wc.hCursor = NULL;
 +
 +		// background color is not used
 +		if (clearBg)
 +		{
 +			wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
 +		}
 +		else
 +		{
 +			wc.hbrBackground = (HBRUSH) NULL;
 +		}
 +
 +		// we don't use windows menus
 +		wc.lpszMenuName = NULL;
 +
 +		wc.lpszClassName = mWindowClassName;
 +
 +		if (!RegisterClass(&wc))
 +		{
 +			OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), 
 +				mCallbacks->translateString("MBError"), OSMB_OK);
 +			return;
 +		}
 +		sIsClassRegistered = TRUE;
 +	}
 +
 +	//-----------------------------------------------------------------------
 +	// Get the current refresh rate
 +	//-----------------------------------------------------------------------
 +
 +	DEVMODE dev_mode;
 +	DWORD current_refresh;
 +	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
 +	{
 +		current_refresh = dev_mode.dmDisplayFrequency;
 +		mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight);
 +	}
 +	else
 +	{
 +		current_refresh = 60;
 +	}
 +
 +	//-----------------------------------------------------------------------
 +	// Drop resolution and go fullscreen
 +	// use a display mode with our desired size and depth, with a refresh
 +	// rate as close at possible to the users' default
 +	//-----------------------------------------------------------------------
 +	if (mFullscreen)
 +	{
 +		BOOL success = FALSE;
 +		DWORD closest_refresh = 0;
 +
 +		for (S32 mode_num = 0;; mode_num++)
 +		{
 +			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
 +			{
 +				break;
 +			}
 +
 +			if (dev_mode.dmPelsWidth == width &&
 +				dev_mode.dmPelsHeight == height &&
 +				dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
 +			{
 +				success = TRUE;
 +				if ((dev_mode.dmDisplayFrequency - current_refresh)
 +					< (closest_refresh - current_refresh))
 +				{
 +					closest_refresh = dev_mode.dmDisplayFrequency;
 +				}
 +			}
 +		}
 +
 +		if (closest_refresh == 0)
 +		{
 +			LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
 +			success = FALSE;
 +		}
 +
 +		// If we found a good resolution, use it.
 +		if (success)
 +		{
 +			success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
 +		}
 +
 +		// Keep a copy of the actual current device mode in case we minimize 
 +		// and change the screen resolution.   JC
 +		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
 +
 +		// If it failed, we don't want to run fullscreen
 +		if (success)
 +		{
 +			mFullscreen = TRUE;
 +			mFullscreenWidth   = dev_mode.dmPelsWidth;
 +			mFullscreenHeight  = dev_mode.dmPelsHeight;
 +			mFullscreenBits    = dev_mode.dmBitsPerPel;
 +			mFullscreenRefresh = dev_mode.dmDisplayFrequency;
 +
 +			LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
 +				<< "x"   << dev_mode.dmPelsHeight
 +				<< "x"   << dev_mode.dmBitsPerPel
 +				<< " @ " << dev_mode.dmDisplayFrequency
 +				<< LL_ENDL;
 +		}
 +		else
 +		{
 +			mFullscreen = FALSE;
 +			mFullscreenWidth   = -1;
 +			mFullscreenHeight  = -1;
 +			mFullscreenBits    = -1;
 +			mFullscreenRefresh = -1;
 +
 +			std::map<std::string,std::string> args;
 +			args["[WIDTH]"] = llformat("%d", width);
 +			args["[HEIGHT]"] = llformat ("%d", height);
 +			OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args),
 +				mCallbacks->translateString("MBError"), OSMB_OK);
 +		}
 +	}
 +
 +	// TODO: add this after resolving _WIN32_WINNT issue
 +	//	if (!fullscreen)
 +	//	{
 +	//		TRACKMOUSEEVENT track_mouse_event;
 +	//		track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
 +	//		track_mouse_event.dwFlags = TME_LEAVE;
 +	//		track_mouse_event.hwndTrack = mWindowHandle;
 +	//		track_mouse_event.dwHoverTime = HOVER_DEFAULT;
 +	//		TrackMouseEvent( &track_mouse_event ); 
 +	//	}
 +
 +
 +	//-----------------------------------------------------------------------
 +	// Create GL drawing context
 +	//-----------------------------------------------------------------------
 +	LLCoordScreen windowPos(x,y);
 +	LLCoordScreen windowSize(window_rect.right - window_rect.left,
 +							 window_rect.bottom - window_rect.top);
 +	if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos))
 +	{
 +		return;
 +	}
 +	
 +	//start with arrow cursor
 +	initCursors();
 +	setCursor( UI_CURSOR_ARROW );
 +
 +	// Initialize (boot strap) the Language text input management,
 +	// based on the system's (or user's) default settings.
 +	allowLanguageTextInput(NULL, FALSE);
 +}
 +
 +
 +LLWindowWin32::~LLWindowWin32()
 +{
 +	delete mDragDrop;
 +
 +	delete [] mWindowTitle;
 +	mWindowTitle = NULL;
 +
 +	delete [] mSupportedResolutions;
 +	mSupportedResolutions = NULL;
 +
 +	delete mWindowClassName;
 +	mWindowClassName = NULL;
 +}
 +
 +void LLWindowWin32::show()
 +{
 +	ShowWindow(mWindowHandle, SW_SHOW);
 +	SetForegroundWindow(mWindowHandle);
 +	SetFocus(mWindowHandle);
 +}
 +
 +void LLWindowWin32::hide()
 +{
 +	setMouseClipping(FALSE);
 +	ShowWindow(mWindowHandle, SW_HIDE);
 +}
 +
 +void LLWindowWin32::minimize()
 +{
 +	setMouseClipping(FALSE);
 +	showCursor();
 +	ShowWindow(mWindowHandle, SW_MINIMIZE);
 +}
 +
 +
 +void LLWindowWin32::restore()
 +{
 +	ShowWindow(mWindowHandle, SW_RESTORE);
 +	SetForegroundWindow(mWindowHandle);
 +	SetFocus(mWindowHandle);
 +}
 +
 +
 +// close() destroys all OS-specific code associated with a window.
 +// Usually called from LLWindowManager::destroyWindow()
 +void LLWindowWin32::close()
 +{
 +	LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL;
 +	// Is window is already closed?
 +	if (!mWindowHandle)
 +	{
 +		return;
 +	}
 +
 +	mDragDrop->reset();
 +
 +	// Make sure cursor is visible and we haven't mangled the clipping state.
 +	setMouseClipping(FALSE);
 +	showCursor();
 +
 +	// Go back to screen mode written in the registry.
 +	if (mFullscreen)
 +	{
 +		resetDisplayResolution();
 +	}
 +
 +	// Clean up remaining GL state
 +	LL_DEBUGS("Window") << "Shutting down GL" << LL_ENDL;
 +	gGLManager.shutdownGL();
 +
 +	LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL;
 +	if (mhRC)
 +	{
 +		if (!wglMakeCurrent(NULL, NULL))
 +		{
 +			LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
 +		}
 +
 +		if (!wglDeleteContext(mhRC))
 +		{
 +			LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
 +		}
 +
 +		mhRC = NULL;
 +	}
 +
 +	// Restore gamma to the system values.
 +	restoreGamma();
 +
 +	if (mhDC && !ReleaseDC(mWindowHandle, mhDC))
 +	{
 +		LL_WARNS("Window") << "Release of ghDC failed" << LL_ENDL;
 +		mhDC = NULL;
 +	}
 +
 +	LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
 +	
 +	// Don't process events in our mainWindowProc any longer.
 +	SetWindowLong(mWindowHandle, GWL_USERDATA, NULL);
 +
 +	// Make sure we don't leave a blank toolbar button.
 +	ShowWindow(mWindowHandle, SW_HIDE);
 +
 +	// This causes WM_DESTROY to be sent *immediately*
 +	if (!DestroyWindow(mWindowHandle))
 +	{
 +		OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
 +			mCallbacks->translateString("MBShutdownErr"),
 +			OSMB_OK);
 +	}
 +
 +	mWindowHandle = NULL;
 +}
 +
 +BOOL LLWindowWin32::isValid()
 +{
 +	return (mWindowHandle != NULL);
 +}
 +
 +BOOL LLWindowWin32::getVisible()
 +{
 +	return (mWindowHandle && IsWindowVisible(mWindowHandle));
 +}
 +
 +BOOL LLWindowWin32::getMinimized()
 +{
 +	return (mWindowHandle && IsIconic(mWindowHandle));
 +}
 +
 +BOOL LLWindowWin32::getMaximized()
 +{
 +	return (mWindowHandle && IsZoomed(mWindowHandle));
 +}
 +
 +BOOL LLWindowWin32::maximize()
 +{
 +	BOOL success = FALSE;
 +	if (!mWindowHandle) return success;
 +
 +	WINDOWPLACEMENT placement;
 +	placement.length = sizeof(WINDOWPLACEMENT);
 +
 +	success = GetWindowPlacement(mWindowHandle, &placement);
 +	if (!success) return success;
 +
 +	placement.showCmd = SW_MAXIMIZE;
 +
 +	success = SetWindowPlacement(mWindowHandle, &placement);
 +	return success;
 +}
 +
 +BOOL LLWindowWin32::getFullscreen()
 +{
 +	return mFullscreen;
 +}
 +
 +BOOL LLWindowWin32::getPosition(LLCoordScreen *position)
 +{
 +	RECT window_rect;
 +
 +	if (!mWindowHandle ||
 +		!GetWindowRect(mWindowHandle, &window_rect) ||
 +		NULL == position)
 +	{
 +		return FALSE;
 +	}
 +
 +	position->mX = window_rect.left;
 +	position->mY = window_rect.top;
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::getSize(LLCoordScreen *size)
 +{
 +	RECT window_rect;
 +
 +	if (!mWindowHandle ||
 +		!GetWindowRect(mWindowHandle, &window_rect) ||
 +		NULL == size)
 +	{
 +		return FALSE;
 +	}
 +
 +	size->mX = window_rect.right - window_rect.left;
 +	size->mY = window_rect.bottom - window_rect.top;
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::getSize(LLCoordWindow *size)
 +{
 +	RECT client_rect;
 +
 +	if (!mWindowHandle ||
 +		!GetClientRect(mWindowHandle, &client_rect) ||
 +		NULL == size)
 +	{
 +		return FALSE;
 +	}
 +
 +	size->mX = client_rect.right - client_rect.left;
 +	size->mY = client_rect.bottom - client_rect.top;
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::setPosition(const LLCoordScreen position)
 +{
 +	LLCoordScreen size;
 +
 +	if (!mWindowHandle)
 +	{
 +		return FALSE;
 +	}
 +	getSize(&size);
 +	moveWindow(position, size);
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::setSize(const LLCoordScreen size)
 +{
 +	LLCoordScreen position;
 +
 +	getPosition(&position);
 +	if (!mWindowHandle)
 +	{
 +		return FALSE;
 +	}
 +
 +	moveWindow(position, size);
 +	return TRUE;
 +}
 +
 +// changing fullscreen resolution
 +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
 +{
 +	GLuint	pixel_format;
 +	DEVMODE dev_mode;
 +	DWORD	current_refresh;
 +	DWORD	dw_ex_style;
 +	DWORD	dw_style;
 +	RECT	window_rect;
 +	S32 width = size.mX;
 +	S32 height = size.mY;
 +	BOOL auto_show = FALSE;
 +
 +	if (mhRC)
 +	{
 +		auto_show = TRUE;
 +		resetDisplayResolution();
 +	}
 +
 +	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
 +	{
 +		current_refresh = dev_mode.dmDisplayFrequency;
 +	}
 +	else
 +	{
 +		current_refresh = 60;
 +	}
 +
 +	gGLManager.shutdownGL();
 +	//destroy gl context
 +	if (mhRC)
 +	{
 +		if (!wglMakeCurrent(NULL, NULL))
 +		{
 +			LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL;
 +		}
 +
 +		if (!wglDeleteContext(mhRC))
 +		{
 +			LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL;
 +		}
 +
 +		mhRC = NULL;
 +	}
 +
 +	if (fullscreen)
 +	{
 +		mFullscreen = TRUE;
 +		BOOL success = FALSE;
 +		DWORD closest_refresh = 0;
 +
 +		for (S32 mode_num = 0;; mode_num++)
 +		{
 +			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
 +			{
 +				break;
 +			}
 +
 +			if (dev_mode.dmPelsWidth == width &&
 +				dev_mode.dmPelsHeight == height &&
 +				dev_mode.dmBitsPerPel == BITS_PER_PIXEL)
 +			{
 +				success = TRUE;
 +				if ((dev_mode.dmDisplayFrequency - current_refresh)
 +					< (closest_refresh - current_refresh))
 +				{
 +					closest_refresh = dev_mode.dmDisplayFrequency;
 +				}
 +			}
 +		}
 +
 +		if (closest_refresh == 0)
 +		{
 +			LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL;
 +			return FALSE;
 +		}
 +
 +		// If we found a good resolution, use it.
 +		if (success)
 +		{
 +			success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh);
 +		}
 +
 +		// Keep a copy of the actual current device mode in case we minimize 
 +		// and change the screen resolution.   JC
 +		EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode);
 +
 +		if (success)
 +		{
 +			mFullscreen = TRUE;
 +			mFullscreenWidth   = dev_mode.dmPelsWidth;
 +			mFullscreenHeight  = dev_mode.dmPelsHeight;
 +			mFullscreenBits    = dev_mode.dmBitsPerPel;
 +			mFullscreenRefresh = dev_mode.dmDisplayFrequency;
 +
 +			LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth
 +				<< "x"   << dev_mode.dmPelsHeight
 +				<< "x"   << dev_mode.dmBitsPerPel
 +				<< " @ " << dev_mode.dmDisplayFrequency
 +				<< LL_ENDL;
 +
 +			window_rect.left = (long) 0;
 +			window_rect.right = (long) width;			// Windows GDI rects don't include rightmost pixel
 +			window_rect.top = (long) 0;
 +			window_rect.bottom = (long) height;
 +			dw_ex_style = WS_EX_APPWINDOW;
 +			dw_style = WS_POPUP;
 +
 +			// Move window borders out not to cover window contents
 +			AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style);
 +		}
 +		// If it failed, we don't want to run fullscreen
 +		else
 +		{
 +			mFullscreen = FALSE;
 +			mFullscreenWidth   = -1;
 +			mFullscreenHeight  = -1;
 +			mFullscreenBits    = -1;
 +			mFullscreenRefresh = -1;
 +
 +			LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL;
 +			return FALSE;
 +		}
 +	}
 +	else
 +	{
 +		mFullscreen = FALSE;
 +		window_rect.left = (long) (posp ? posp->mX : 0);
 +		window_rect.right = (long) width + window_rect.left;			// Windows GDI rects don't include rightmost pixel
 +		window_rect.top = (long) (posp ? posp->mY : 0);
 +		window_rect.bottom = (long) height + window_rect.top;
 +		// Window with an edge
 +		dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
 +		dw_style = WS_OVERLAPPEDWINDOW;
 +	}
 +
 +	// don't post quit messages when destroying old windows
 +	mPostQuit = FALSE;
 +
 +	// create window
 +	DestroyWindow(mWindowHandle);
 +	mWindowHandle = CreateWindowEx(dw_ex_style,
 +		mWindowClassName,
 +		mWindowTitle,
 +		WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
 +		window_rect.left,								// x pos
 +		window_rect.top,								// y pos
 +		window_rect.right - window_rect.left,			// width
 +		window_rect.bottom - window_rect.top,			// height
 +		NULL,
 +		NULL,
 +		mhInstance,
 +		NULL);
 +
 +	//-----------------------------------------------------------------------
 +	// Create GL drawing context
 +	//-----------------------------------------------------------------------
 +	static PIXELFORMATDESCRIPTOR pfd =
 +	{
 +		sizeof(PIXELFORMATDESCRIPTOR), 
 +			1,
 +			PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, 
 +			PFD_TYPE_RGBA,
 +			BITS_PER_PIXEL,
 +			0, 0, 0, 0, 0, 0,	// RGB bits and shift, unused
 +			8,					// alpha bits
 +			0,					// alpha shift
 +			0,					// accum bits
 +			0, 0, 0, 0,			// accum RGBA
 +			24,					// depth bits
 +			8,					// stencil bits, avi added for stencil test
 +			0,
 +			PFD_MAIN_PLANE,
 +			0,
 +			0, 0, 0
 +	};
 +
 +	if (!(mhDC = GetDC(mWindowHandle)))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBDevContextErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!(pixel_format = ChoosePixelFormat(mhDC, &pfd)))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	// Verify what pixel format we actually received.
 +	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
 +		&pfd))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (pfd.cColorBits < 32)
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (pfd.cAlphaBits < 8)
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBAlpha"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!SetPixelFormat(mhDC, pixel_format, &pfd))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!(mhRC = wglCreateContext(mhDC)))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBGLContextErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!wglMakeCurrent(mhDC, mhRC))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"),
 +			mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	gGLManager.initWGL();
 +
 +	if (wglChoosePixelFormatARB)
 +	{
 +		// OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we
 +		// can get exactly what we want.
 +		GLint attrib_list[256];
 +		S32 cur_attrib = 0;
 +
 +		attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB;
 +		attrib_list[cur_attrib++] = 24;
 +
 +		attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB;
 +		attrib_list[cur_attrib++] = 8;
 +
 +		attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB;
 +		attrib_list[cur_attrib++] = GL_TRUE;
 +
 +		attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB;
 +		attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB;
 +
 +		attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB;
 +		attrib_list[cur_attrib++] = GL_TRUE;
 +
 +		attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB;
 +		attrib_list[cur_attrib++] = GL_TRUE;
 +
 +		attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB;
 +		attrib_list[cur_attrib++] = 24;
 +
 +		attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB;
 +		attrib_list[cur_attrib++] = 8;
 +
 +		U32 end_attrib = 0;
 +		if (mFSAASamples > 0)
 +		{
 +			end_attrib = cur_attrib;
 +			attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB;
 +			attrib_list[cur_attrib++] = GL_TRUE;
 +
 +			attrib_list[cur_attrib++] = WGL_SAMPLES_ARB;
 +			attrib_list[cur_attrib++] = mFSAASamples;
 +		}
 +
 +		// End the list
 +		attrib_list[cur_attrib++] = 0;
 +
 +		GLint pixel_formats[256];
 +		U32 num_formats = 0;
 +
 +		// First we try and get a 32 bit depth pixel format
 +		BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
 +		if (!result)
 +		{
 +			close();
 +			show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit");
 +			return FALSE;
 +		}
 +
 +		if (!num_formats)
 +		{
 +			if (end_attrib > 0)
 +			{
 +				LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL;
 +				attrib_list[end_attrib] = 0;
 +
 +				BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
 +				if (!result)
 +				{
 +					close();
 +					show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA");
 +					return FALSE;
 +				}
 +			}
 +
 +			if (!num_formats)
 +			{
 +				LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL;
 +				// Try 24-bit format
 +				attrib_list[1] = 24;
 +				BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
 +				if (!result)
 +				{
 +					close();
 +					show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit");
 +					return FALSE;
 +				}
 +
 +				if (!num_formats)
 +				{
 +					LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL;
 +					attrib_list[1] = 16;
 +					BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats);
 +					if (!result || !num_formats)
 +					{
 +						close();
 +						show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit");
 +						return FALSE;
 +					}
 +				}
 +			}
 +
 +			LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL;
 +		}
 +
 +		
 +
 +		S32 swap_method = 0;
 +		S32 cur_format = num_formats-1;
 +		GLint swap_query = WGL_SWAP_METHOD_ARB;
 +
 +		BOOL found_format = FALSE;
 +
 +		while (!found_format && wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
 +		{
 +			if (swap_method == WGL_SWAP_UNDEFINED_ARB || cur_format <= 0)
 +			{
 +				found_format = TRUE;
 +			}
 +			else
 +			{
 +				--cur_format;
 +			}
 +		}
 +		
 +		pixel_format = pixel_formats[cur_format];
 +		
 +		if (mhDC != 0)											// Does The Window Have A Device Context?
 +		{
 +			wglMakeCurrent(mhDC, 0);							// Set The Current Active Rendering Context To Zero
 +			if (mhRC != 0)										// Does The Window Have A Rendering Context?
 +			{
 +				wglDeleteContext (mhRC);							// Release The Rendering Context
 +				mhRC = 0;										// Zero The Rendering Context
 +
 +			}
 +			ReleaseDC (mWindowHandle, mhDC);						// Release The Device Context
 +			mhDC = 0;											// Zero The Device Context
 +		}
 +		DestroyWindow (mWindowHandle);									// Destroy The Window
 +		
 +
 +		mWindowHandle = CreateWindowEx(dw_ex_style,
 +			mWindowClassName,
 +			mWindowTitle,
 +			WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style,
 +			window_rect.left,								// x pos
 +			window_rect.top,								// y pos
 +			window_rect.right - window_rect.left,			// width
 +			window_rect.bottom - window_rect.top,			// height
 +			NULL,
 +			NULL,
 +			mhInstance,
 +			NULL);
 +
 +		if (!(mhDC = GetDC(mWindowHandle)))
 +		{
 +			close();
 +			OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 +			return FALSE;
 +		}
 +
 +		if (!SetPixelFormat(mhDC, pixel_format, &pfd))
 +		{
 +			close();
 +			OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"),
 +				mCallbacks->translateString("MBError"), OSMB_OK);
 +			return FALSE;
 +		}
 +
 +		if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method))
 +		{
 +			switch (swap_method)
 +			{
 +			case WGL_SWAP_EXCHANGE_ARB:
 +				mSwapMethod = SWAP_METHOD_EXCHANGE;
 +				LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL;
 +				break;
 +			case WGL_SWAP_COPY_ARB:
 +				mSwapMethod = SWAP_METHOD_COPY;
 +				LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL;
 +				break;
 +			case WGL_SWAP_UNDEFINED_ARB:
 +				mSwapMethod = SWAP_METHOD_UNDEFINED;
 +				LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL;
 +				break;
 +			default:
 +				mSwapMethod = SWAP_METHOD_UNDEFINED;
 +				LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL;
 +				break;
 +			}
 +		}		
 +	}
 +	else
 +	{
 +		LL_WARNS("Window") << "No wgl_ARB_pixel_format extension, using default ChoosePixelFormat!" << LL_ENDL;
 +	}
 +
 +	// Verify what pixel format we actually received.
 +	if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR),
 +		&pfd))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) 
 +		<< " Alpha Bits " << S32(pfd.cAlphaBits)
 +		<< " Depth Bits " << S32(pfd.cDepthBits) 
 +		<< LL_ENDL;
 +
 +	// make sure we have 32 bits per pixel
 +	if (pfd.cColorBits < 32 || GetDeviceCaps(mhDC, BITSPIXEL) < 32)
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBTrueColorWindow"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (pfd.cAlphaBits < 8)
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBAlpha"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!(mhRC = wglCreateContext(mhDC)))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!wglMakeCurrent(mhDC, mhRC))
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	if (!gGLManager.initGL())
 +	{
 +		close();
 +		OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK);
 +		return FALSE;
 +	}
 +
 +	// Disable vertical sync for swap
 +	if (disable_vsync && wglSwapIntervalEXT)
 +	{
 +		LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL;
 +		wglSwapIntervalEXT(0);
 +	}
 +	else
 +	{
 +		LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL;
 +	}
 +
 +	SetWindowLong(mWindowHandle, GWL_USERDATA, (U32)this);
 +
 +	// register this window as handling drag/drop events from the OS
 +	DragAcceptFiles( mWindowHandle, TRUE );
 +
 +	mDragDrop->init( mWindowHandle );
 +	
 +	//register joystick timer callback
 +	SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer
 +
 +	// ok to post quit messages now
 +	mPostQuit = TRUE;
 +
 +	if (auto_show)
 +	{
 +		show();
 +		glClearColor(0.0f, 0.0f, 0.0f, 0.f);
 +		glClear(GL_COLOR_BUFFER_BIT);
 +		swapBuffers();
 +	}
 +
 +	return TRUE;
 +}
 +
 +void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size )
 +{
 +	if( mIsMouseClipping )
 +	{
 +		RECT client_rect_in_screen_space;
 +		if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
 +		{
 +			ClipCursor( &client_rect_in_screen_space );
 +		}
 +	}
 +
 +	// if the window was already maximized, MoveWindow seems to still set the maximized flag even if
 +	// the window is smaller than maximized.
 +	// So we're going to do a restore first (which is a ShowWindow call) (SL-44655).
 +
 +	// THIS CAUSES DEV-15484 and DEV-15949 
 +	//ShowWindow(mWindowHandle, SW_RESTORE);
 +	// NOW we can call MoveWindow
 +	MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE);
 +}
 +
 +BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position)
 +{
 +	LLCoordScreen screen_pos;
 +
 +	mMousePositionModified = TRUE;
 +	if (!mWindowHandle)
 +	{
 +		return FALSE;
 +	}
 +
 +	if (!convertCoords(position, &screen_pos))
 +	{
 +		return FALSE;
 +	}
 +
 +	// Inform the application of the new mouse position (needed for per-frame
 +	// hover/picking to function).
 +	LLCoordGL gl_pos;
 +	convertCoords(position, &gl_pos);
 +	mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
 +	
 +	// DEV-18951 VWR-8524 Camera moves wildly when alt-clicking.
 +	// Because we have preemptively notified the application of the new
 +	// mouse position via handleMouseMove() above, we need to clear out
 +	// any stale mouse move events.  RN/JC
 +	MSG msg;
 +	while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
 +	{ }
 +
 +	return SetCursorPos(screen_pos.mX, screen_pos.mY);
 +}
 +
 +BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position)
 +{
 +	POINT cursor_point;
 +	LLCoordScreen screen_pos;
 +
 +	if (!mWindowHandle ||
 +		!GetCursorPos(&cursor_point))
 +	{
 +		return FALSE;
 +	}
 +
 +	screen_pos.mX = cursor_point.x;
 +	screen_pos.mY = cursor_point.y;
 +
 +	return convertCoords(screen_pos, position);
 +}
 +
 +void LLWindowWin32::hideCursor()
 +{
 +	while (ShowCursor(FALSE) >= 0)
 +	{
 +		// nothing, wait for cursor to push down
 +	}
 +	mCursorHidden = TRUE;
 +	mHideCursorPermanent = TRUE;
 +}
 +
 +void LLWindowWin32::showCursor()
 +{
 +	// makes sure the cursor shows up
 +	while (ShowCursor(TRUE) < 0)
 +	{
 +		// do nothing, wait for cursor to pop out
 +	}
 +	mCursorHidden = FALSE;
 +	mHideCursorPermanent = FALSE;
 +}
 +
 +void LLWindowWin32::showCursorFromMouseMove()
 +{
 +	if (!mHideCursorPermanent)
 +	{
 +		showCursor();
 +	}
 +}
 +
 +void LLWindowWin32::hideCursorUntilMouseMove()
 +{
 +	if (!mHideCursorPermanent)
 +	{
 +		hideCursor();
 +		mHideCursorPermanent = FALSE;
 +	}
 +}
 +
 +BOOL LLWindowWin32::isCursorHidden()
 +{
 +	return mCursorHidden;
 +}
 +
 +
 +HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name)
 +{
 +	return (HCURSOR)LoadImage(mhInstance,
 +							  name,
 +							  IMAGE_CURSOR,
 +							  0,	// default width
 +							  0,	// default height
 +							  LR_DEFAULTCOLOR);
 +}
 +
 +
 +void LLWindowWin32::initCursors()
 +{
 +	mCursor[ UI_CURSOR_ARROW ]		= LoadCursor(NULL, IDC_ARROW);
 +	mCursor[ UI_CURSOR_WAIT ]		= LoadCursor(NULL, IDC_WAIT);
 +	mCursor[ UI_CURSOR_HAND ]		= LoadCursor(NULL, IDC_HAND);
 +	mCursor[ UI_CURSOR_IBEAM ]		= LoadCursor(NULL, IDC_IBEAM);
 +	mCursor[ UI_CURSOR_CROSS ]		= LoadCursor(NULL, IDC_CROSS);
 +	mCursor[ UI_CURSOR_SIZENWSE ]	= LoadCursor(NULL, IDC_SIZENWSE);
 +	mCursor[ UI_CURSOR_SIZENESW ]	= LoadCursor(NULL, IDC_SIZENESW);
 +	mCursor[ UI_CURSOR_SIZEWE ]		= LoadCursor(NULL, IDC_SIZEWE);  
 +	mCursor[ UI_CURSOR_SIZENS ]		= LoadCursor(NULL, IDC_SIZENS);  
 +	mCursor[ UI_CURSOR_NO ]			= LoadCursor(NULL, IDC_NO);
 +	mCursor[ UI_CURSOR_WORKING ]	= LoadCursor(NULL, IDC_APPSTARTING); 
 +
 +	HMODULE module = GetModuleHandle(NULL);
 +	mCursor[ UI_CURSOR_TOOLGRAB ]	= LoadCursor(module, TEXT("TOOLGRAB"));
 +	mCursor[ UI_CURSOR_TOOLLAND ]	= LoadCursor(module, TEXT("TOOLLAND"));
 +	mCursor[ UI_CURSOR_TOOLFOCUS ]	= LoadCursor(module, TEXT("TOOLFOCUS"));
 +	mCursor[ UI_CURSOR_TOOLCREATE ]	= LoadCursor(module, TEXT("TOOLCREATE"));
 +	mCursor[ UI_CURSOR_ARROWDRAG ]	= LoadCursor(module, TEXT("ARROWDRAG"));
 +	mCursor[ UI_CURSOR_ARROWCOPY ]	= LoadCursor(module, TEXT("ARROWCOPY"));
 +	mCursor[ UI_CURSOR_ARROWDRAGMULTI ]	= LoadCursor(module, TEXT("ARROWDRAGMULTI"));
 +	mCursor[ UI_CURSOR_ARROWCOPYMULTI ]	= LoadCursor(module, TEXT("ARROWCOPYMULTI"));
 +	mCursor[ UI_CURSOR_NOLOCKED ]	= LoadCursor(module, TEXT("NOLOCKED"));
 +	mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED"));
 +	mCursor[ UI_CURSOR_GRABLOCKED ]	= LoadCursor(module, TEXT("GRABLOCKED"));
 +	mCursor[ UI_CURSOR_TOOLTRANSLATE ]	= LoadCursor(module, TEXT("TOOLTRANSLATE"));
 +	mCursor[ UI_CURSOR_TOOLROTATE ]	= LoadCursor(module, TEXT("TOOLROTATE")); 
 +	mCursor[ UI_CURSOR_TOOLSCALE ]	= LoadCursor(module, TEXT("TOOLSCALE"));
 +	mCursor[ UI_CURSOR_TOOLCAMERA ]	= LoadCursor(module, TEXT("TOOLCAMERA"));
 +	mCursor[ UI_CURSOR_TOOLPAN ]	= LoadCursor(module, TEXT("TOOLPAN"));
 +	mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN"));
 +	mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3"));
 +	mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE"));
 +
 +	// Color cursors
 +	mCursor[UI_CURSOR_TOOLPLAY] = loadColorCursor(TEXT("TOOLPLAY"));
 +	mCursor[UI_CURSOR_TOOLPAUSE] = loadColorCursor(TEXT("TOOLPAUSE"));
 +	mCursor[UI_CURSOR_TOOLMEDIAOPEN] = loadColorCursor(TEXT("TOOLMEDIAOPEN"));
 +
 +	// Note: custom cursors that are not found make LoadCursor() return NULL.
 +	for( S32 i = 0; i < UI_CURSOR_COUNT; i++ )
 +	{
 +		if( !mCursor[i] )
 +		{
 +			mCursor[i] = LoadCursor(NULL, IDC_ARROW);
 +		}
 +	}
 +}
 +
 +
 +
 +void LLWindowWin32::setCursor(ECursorType cursor)
 +{
 +	if (cursor == UI_CURSOR_ARROW
 +		&& mBusyCount > 0)
 +	{
 +		cursor = UI_CURSOR_WORKING;
 +	}
 +
 +	if( mCurrentCursor != cursor )
 +	{
 +		mCurrentCursor = cursor;
 +		SetCursor( mCursor[cursor] );
 +	}
 +}
 +
 +ECursorType LLWindowWin32::getCursor() const
 +{
 +	return mCurrentCursor;
 +}
 +
 +void LLWindowWin32::captureMouse()
 +{
 +	SetCapture(mWindowHandle);
 +}
 +
 +void LLWindowWin32::releaseMouse()
 +{
 +	// *NOTE:Mani ReleaseCapture will spawn new windows messages...
 +	// which will in turn call our MainWindowProc. It therefore requires
 +	// pausing *and more importantly resumption* of the mainlooptimeout...
 +	// just like DispatchMessage below.
 +	mCallbacks->handlePauseWatchdog(this);
 +	ReleaseCapture();
 +	mCallbacks->handleResumeWatchdog(this);
 +}
 +
 +
 +void LLWindowWin32::delayInputProcessing()
 +{
 +	mInputProcessingPaused = TRUE;
 +}
 +
 +void LLWindowWin32::gatherInput()
 +{
 +	MSG		msg;
 +	int		msg_count = 0;
 +
 +	LLMemType m1(LLMemType::MTYPE_GATHER_INPUT);
 +
 +	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && msg_count < MAX_MESSAGE_PER_UPDATE)
 +	{
 +		mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput");
 +		TranslateMessage(&msg);
 +
 +		// turn watchdog off in here to not fail if windows is doing something wacky
 +		mCallbacks->handlePauseWatchdog(this);
 +		DispatchMessage(&msg);
 +		mCallbacks->handleResumeWatchdog(this);
 +		msg_count++;
 +
 +		if ( mInputProcessingPaused )
 +		{
 +			break;
 +		}
 +		/* Attempted workaround for problem where typing fast and hitting
 +		   return would result in only part of the text being sent. JC
 +
 +		BOOL key_posted = TranslateMessage(&msg);
 +		DispatchMessage(&msg);
 +		msg_count++;
 +
 +		// If a key was translated, a WM_CHAR might have been posted to the end
 +		// of the event queue.  We need it immediately.
 +		if (key_posted && msg.message == WM_KEYDOWN)
 +		{
 +			if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE))
 +			{
 +				TranslateMessage(&msg);
 +				DispatchMessage(&msg);
 +				msg_count++;
 +			}
 +		}
 +		*/
 +		mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput");
 +		// For async host by name support.  Really hacky.
 +		if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message))
 +		{
 +			gAsyncMsgCallback(msg);
 +		}
 +	}
 +
 +	mInputProcessingPaused = FALSE;
 +
 +	// clear this once we've processed all mouse messages that might have occurred after
 +	// we slammed the mouse position
 +	mMousePositionModified = FALSE;
 +}
 +
 +static LLFastTimer::DeclareTimer FTM_KEYHANDLER("Handle Keyboard");
 +static LLFastTimer::DeclareTimer FTM_MOUSEHANDLER("Handle Mouse");
 +
 +LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param)
 +{
 +	LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLong(h_wnd, GWL_USERDATA);
 +
 +
 +	if (NULL != window_imp)
 +	{
 +		window_imp->mCallbacks->handleResumeWatchdog(window_imp);
 +		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc");
 +		// Has user provided their own window callback?
 +		if (NULL != window_imp->mWndProc)
 +		{
 +			if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param))
 +			{
 +				// user has handled window message
 +				return 0;
 +			}
 +		}
 +
 +		window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc");
 +		
 +		// Juggle to make sure we can get negative positions for when
 +		// mouse is outside window.
 +		LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param));
 +
 +		// This doesn't work, as LOWORD returns unsigned short.
 +		//LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param));
 +		LLCoordGL gl_coord;
 +
 +		// pass along extended flag in mask
 +		MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0;
 +		BOOL eat_keystroke = TRUE;
 +
 +		switch(u_msg)
 +		{
 +			RECT	update_rect;
 +			S32		update_width;
 +			S32		update_height;
 +
 +		case WM_TIMER:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER");
 +			window_imp->mCallbacks->handleTimerEvent(window_imp);
 +			break;
 +
 +		case WM_DEVICECHANGE:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "  WM_DEVICECHANGE: wParam=" << w_param 
 +						<< "; lParam=" << l_param << llendl;
 +			}
 +			if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL)
 +			{
 +				if (window_imp->mCallbacks->handleDeviceChange(window_imp))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_PAINT:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT");
 +			GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE);
 +			update_width = update_rect.right - update_rect.left + 1;
 +			update_height = update_rect.bottom - update_rect.top + 1;
 +			window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top,
 +				update_width, update_height);
 +			break;
 +		case WM_PARENTNOTIFY:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY");
 +			u_msg = u_msg;
 +			break;
 +
 +		case WM_SETCURSOR:
 +			// This message is sent whenever the cursor is moved in a window.
 +			// You need to set the appropriate cursor appearance.
 +
 +			// Only take control of cursor over client region of window
 +			// This allows Windows(tm) to handle resize cursors, etc.
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR");
 +			if (LOWORD(l_param) == HTCLIENT)
 +			{
 +				SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] );
 +				return 0;
 +			}
 +			break;
 +
 +		case WM_ENTERMENULOOP:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP");
 +			window_imp->mCallbacks->handleWindowBlock(window_imp);
 +			break;
 +
 +		case WM_EXITMENULOOP:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP");
 +			window_imp->mCallbacks->handleWindowUnblock(window_imp);
 +			break;
 +
 +		case WM_ACTIVATEAPP:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP");
 +			{
 +				// This message should be sent whenever the app gains or loses focus.
 +				BOOL activating = (BOOL) w_param;
 +				BOOL minimized = window_imp->getMinimized();
 +
 +				if (gDebugWindowProc)
 +				{
 +					LL_INFOS("Window") << "WINDOWPROC ActivateApp "
 +						<< " activating " << S32(activating)
 +						<< " minimized " << S32(minimized)
 +						<< " fullscreen " << S32(window_imp->mFullscreen)
 +						<< LL_ENDL;
 +				}
 +
 +				if (window_imp->mFullscreen)
 +				{
 +					// When we run fullscreen, restoring or minimizing the app needs 
 +					// to switch the screen resolution
 +					if (activating)
 +					{
 +						window_imp->setFullscreenResolution();
 +						window_imp->restore();
 +					}
 +					else
 +					{
 +						window_imp->minimize();
 +						window_imp->resetDisplayResolution();
 +					}
 +				}
 +
 +				window_imp->mCallbacks->handleActivateApp(window_imp, activating);
 +
 +				break;
 +			}
 +
 +		case WM_ACTIVATE:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE");
 +			{
 +				// Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE
 +				BOOL activating = (LOWORD(w_param) != WA_INACTIVE);
 +
 +				BOOL minimized = BOOL(HIWORD(w_param));
 +
 +				if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor)
 +				{
 +					window_imp->interruptLanguageTextInput();
 +				}
 +
 +				// JC - I'm not sure why, but if we don't report that we handled the 
 +				// WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work 
 +				// properly when we run fullscreen.
 +				if (gDebugWindowProc)
 +				{
 +					LL_INFOS("Window") << "WINDOWPROC Activate "
 +						<< " activating " << S32(activating) 
 +						<< " minimized " << S32(minimized)
 +						<< LL_ENDL;
 +				}
 +
 +				// Don't handle this.
 +				break;
 +			}
 +
 +		case WM_QUERYOPEN:
 +			// TODO: use this to return a nice icon
 +			break;
 +
 +		case WM_SYSCOMMAND:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND");
 +			switch(w_param)
 +			{
 +			case SC_KEYMENU: 
 +				// Disallow the ALT key from triggering the default system menu.
 +				return 0;		
 +
 +			case SC_SCREENSAVE:
 +			case SC_MONITORPOWER:
 +				// eat screen save messages and prevent them!
 +				return 0;
 +			}
 +			break;
 +
 +		case WM_CLOSE:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE");
 +			// Will the app allow the window to close?
 +			if (window_imp->mCallbacks->handleCloseRequest(window_imp))
 +			{
 +				// Get the app to initiate cleanup.
 +				window_imp->mCallbacks->handleQuit(window_imp);
 +				// The app is responsible for calling destroyWindow when done with GL
 +			}
 +			return 0;
 +
 +		case WM_DESTROY:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY");
 +			if (window_imp->shouldPostQuit())
 +			{
 +				PostQuitMessage(0);  // Posts WM_QUIT with an exit code of 0
 +			}
 +			return 0;
 +
 +		case WM_COMMAND:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND");
 +			if (!HIWORD(w_param)) // this message is from a menu
 +			{
 +				window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param));
 +			}
 +			break;
 +
 +		case WM_SYSKEYDOWN:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN");
 +			// allow system keys, such as ALT-F4 to be processed by Windows
 +			eat_keystroke = FALSE;
 +		case WM_KEYDOWN:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN");
 +			{
 +				if (gDebugWindowProc)
 +				{
 +					LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN "
 +						<< " key " << S32(w_param) 
 +						<< LL_ENDL;
 +				}
 +				if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke)
 +				{
 +					return 0;
 +				}
 +				// pass on to windows if we didn't handle it
 +				break;
 +			}
 +		case WM_SYSKEYUP:
 +			eat_keystroke = FALSE;
 +		case WM_KEYUP:
 +		{
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP");
 +			LLFastTimer t2(FTM_KEYHANDLER);
 +
 +			if (gDebugWindowProc)
 +			{
 +				LL_INFOS("Window") << "Debug WindowProc WM_KEYUP "
 +					<< " key " << S32(w_param) 
 +					<< LL_ENDL;
 +			}
 +			if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke)
 +			{
 +				return 0;
 +			}
 +
 +			// pass on to windows
 +			break;
 +		}
 +		case WM_IME_SETCONTEXT:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "WM_IME_SETCONTEXT" << llendl;
 +			}
 +			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +			{
 +				l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
 +				// Invoke DefWinProc with the modified LPARAM.
 +			}
 +			break;
 +
 +		case WM_IME_STARTCOMPOSITION:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "WM_IME_STARTCOMPOSITION" << llendl;
 +			}
 +			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +			{
 +				window_imp->handleStartCompositionMessage();
 +				return 0;
 +			}
 +			break;
 +
 +		case WM_IME_ENDCOMPOSITION:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "WM_IME_ENDCOMPOSITION" << llendl;
 +			}
 +			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +			{
 +				return 0;
 +			}
 +			break;
 +
 +		case WM_IME_COMPOSITION:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "WM_IME_COMPOSITION" << llendl;
 +			}
 +			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +			{
 +				window_imp->handleCompositionMessage(l_param);
 +				return 0;
 +			}
 +			break;
 +
 +		case WM_IME_REQUEST:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST");
 +			if (gDebugWindowProc)
 +			{
 +				llinfos << "WM_IME_REQUEST" << llendl;
 +			}
 +			if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +			{
 +				LRESULT result = 0;
 +				if (window_imp->handleImeRequests(w_param, l_param, &result))
 +				{
 +					return result;
 +				}
 +			}
 +			break;
 +
 +		case WM_CHAR:
 +			// Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need
 +			// to figure out how that works. - Doug
 +			//
 +			// ... Well, I don't think so.
 +			// How it works is explained in Win32 API document, but WM_UNICHAR didn't work
 +			// as specified at least on Windows XP SP1 Japanese version.  I have never used
 +			// it since then, and I'm not sure whether it has been fixed now, but I don't think
 +			// it is worth trying.  The good old WM_CHAR works just fine even for supplementary
 +			// characters.  We just need to take care of surrogate pairs sent as two WM_CHAR's
 +			// by ourselves.  It is not that tough.  -- Alissa Sabre @ SL
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR");
 +			if (gDebugWindowProc)
 +			{
 +				LL_INFOS("Window") << "Debug WindowProc WM_CHAR "
 +					<< " key " << S32(w_param) 
 +					<< LL_ENDL;
 +			}
 +			// Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE,
 +			// we *did* processed the event, so I believe we should not pass it to DefWindowProc...
 +			window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE));
 +			return 0;
 +
 +		case WM_LBUTTONDOWN:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +				{
 +					window_imp->interruptLanguageTextInput();
 +				}
 +
 +				// Because we move the cursor position in the app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_LBUTTONDBLCLK:
 +		//RN: ignore right button double clicks for now
 +		//case WM_RBUTTONDBLCLK:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK");
 +				// Because we move the cursor position in the app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) )
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_LBUTTONUP:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				//if (gDebugClicks)
 +				//{
 +				//	LL_INFOS("Window") << "WndProc left button up" << LL_ENDL;
 +				//}
 +				// Because we move the cursor position in the app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_RBUTTONDBLCLK:
 +		case WM_RBUTTONDOWN:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +				{
 +					window_imp->interruptLanguageTextInput();
 +				}
 +
 +				// Because we move the cursor position in the llviewerapp, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_RBUTTONUP:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				// Because we move the cursor position in the app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_MBUTTONDOWN:
 +//		case WM_MBUTTONDBLCLK:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				if (LLWinImm::isAvailable() && window_imp->mPreeditor)
 +				{
 +					window_imp->interruptLanguageTextInput();
 +				}
 +
 +				// Because we move the cursor position in tllviewerhe app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_MBUTTONUP:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP");
 +				LLFastTimer t2(FTM_MOUSEHANDLER);
 +				// Because we move the cursor position in tllviewerhe app, we need to query
 +				// to find out where the cursor at the time the event is handled.
 +				// If we don't do this, many clicks could get buffered up, and if the
 +				// first click changes the cursor position, all subsequent clicks
 +				// will occur at the wrong location.  JC
 +				LLCoordWindow cursor_coord_window;
 +				if (window_imp->mMousePositionModified)
 +				{
 +					window_imp->getCursorPosition(&cursor_coord_window);
 +					window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +				}
 +				else
 +				{
 +					window_imp->convertCoords(window_coord, &gl_coord);
 +				}
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				// generate move event to update mouse coordinates
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask))
 +				{
 +					return 0;
 +				}
 +			}
 +			break;
 +
 +		case WM_MOUSEWHEEL:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL");
 +				static short z_delta = 0;
 +
 +				z_delta += HIWORD(w_param);
 +				// cout << "z_delta " << z_delta << endl;
 +
 +				// current mouse wheels report changes in increments of zDelta (+120, -120)
 +				// Future, higher resolution mouse wheels may report smaller deltas.
 +				// So we sum the deltas and only act when we've exceeded WHEEL_DELTA
 +				//
 +				// If the user rapidly spins the wheel, we can get messages with
 +				// large deltas, like 480 or so.  Thus we need to scroll more quickly.
 +				if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
 +				{
 +					window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA);
 +					z_delta = 0;
 +				}
 +				return 0;
 +			}
 +			/*
 +			// TODO: add this after resolving _WIN32_WINNT issue
 +			case WM_MOUSELEAVE:
 +			{
 +			window_imp->mCallbacks->handleMouseLeave(window_imp);
 +
 +			//				TRACKMOUSEEVENT track_mouse_event;
 +			//				track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT );
 +			//				track_mouse_event.dwFlags = TME_LEAVE;
 +			//				track_mouse_event.hwndTrack = h_wnd;
 +			//				track_mouse_event.dwHoverTime = HOVER_DEFAULT;
 +			//				TrackMouseEvent( &track_mouse_event ); 
 +			return 0;
 +			}
 +			*/
 +			// Handle mouse movement within the window
 +		case WM_MOUSEMOVE:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE");
 +				window_imp->convertCoords(window_coord, &gl_coord);
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +				window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask);
 +				return 0;
 +			}
 +
 +		case WM_SIZE:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE");
 +				S32 width = S32( LOWORD(l_param) );
 +				S32 height = S32( HIWORD(l_param) );
 +
 +				if (gDebugWindowProc)
 +				{
 +					BOOL maximized = ( w_param == SIZE_MAXIMIZED );
 +					BOOL restored  = ( w_param == SIZE_RESTORED );
 +					BOOL minimized = ( w_param == SIZE_MINIMIZED );
 +
 +					LL_INFOS("Window") << "WINDOWPROC Size "
 +						<< width << "x" << height
 +						<< " max " << S32(maximized)
 +						<< " min " << S32(minimized)
 +						<< " rest " << S32(restored)
 +						<< LL_ENDL;
 +				}
 +
 +				// There's an odd behavior with WM_SIZE that I would call a bug. If 
 +				// the window is maximized, and you call MoveWindow() with a size smaller
 +				// than a maximized window, it ends up sending WM_SIZE with w_param set 
 +				// to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work.
 +				// (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see 
 +				// LLWindowWin32::moveWindow in this file). 
 +
 +				// If we are now restored, but we weren't before, this
 +				// means that the window was un-minimized.
 +				if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED)
 +				{
 +					window_imp->mCallbacks->handleActivate(window_imp, TRUE);
 +				}
 +
 +				// handle case of window being maximized from fully minimized state
 +				if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED)
 +				{
 +					window_imp->mCallbacks->handleActivate(window_imp, TRUE);
 +				}
 +
 +				// Also handle the minimization case
 +				if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED)
 +				{
 +					window_imp->mCallbacks->handleActivate(window_imp, FALSE);
 +				}
 +
 +				// Actually resize all of our views
 +				if (w_param != SIZE_MINIMIZED)
 +				{
 +					// Ignore updates for minimizing and minimized "windows"
 +					window_imp->mCallbacks->handleResize(	window_imp, 
 +						LOWORD(l_param), 
 +						HIWORD(l_param) );
 +				}
 +
 +				window_imp->mLastSizeWParam = w_param;
 +
 +				return 0;
 +			}
 +
 +		case WM_SETFOCUS:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS");
 +			if (gDebugWindowProc)
 +			{
 +				LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL;
 +			}
 +			window_imp->mCallbacks->handleFocus(window_imp);
 +			return 0;
 +
 +		case WM_KILLFOCUS:
 +			window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS");
 +			if (gDebugWindowProc)
 +			{
 +				LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL;
 +			}
 +			window_imp->mCallbacks->handleFocusLost(window_imp);
 +			return 0;
 +
 +		case WM_COPYDATA:
 +			{
 +				window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA");
 +				// received a URL
 +				PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param;
 +				window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData);
 +			};
 +			return 0;			
 +
 +		case WM_DROPFILES:
 +			{
 +				// HDROP contains what we need
 +				HDROP hdrop = (HDROP)w_param;
 +
 +				// get location in window space where drop occured and convert to OpenGL coordinate space
 +				POINT pt;
 +				DragQueryPoint( hdrop, &pt );
 +				LLCoordGL gl_coord;
 +				LLCoordWindow cursor_coord_window( pt.x, pt.y );
 +				window_imp->convertCoords(cursor_coord_window, &gl_coord);
 +
 +				// get payload (eventually, this needs to more advanced and grab size of payload dynamically
 +				static char file_name[ 1024 ];
 +				DragQueryFileA( hdrop, 0, file_name, 1024 );
 +				void* url = (void*)( file_name );
 +
 +				// if it's a .URL or .lnk ("shortcut") file
 +				if ( std::string( file_name ).find( ".lnk" ) != std::string::npos ||
 +					  std::string( file_name ).find( ".URL" ) != std::string::npos )
 +				{
 +					// read through file - looks like a 2 line file with second line URL= but who knows..
 +					std::ifstream file_handle( file_name );
 +					if ( file_handle.is_open() )
 +					{
 +						std::string line;
 +						while ( ! file_handle.eof() )
 +						{
 +							std::getline( file_handle, line );
 +							if ( ! file_handle.eof() )
 +							{
 +								std::string prefix( "URL=" );
 +								if ( line.find( prefix, 0 ) != std::string::npos )
 +								{
 +									line = line.substr( 4 );  // skip off the URL= bit
 +									strcpy( (char*)url, line.c_str() );
 +									break;
 +								};
 +							};
 +						};
 +						file_handle.close();
 +					};
 +				};
 +
 +				MASK mask = gKeyboard->currentMask(TRUE);
 +
 +				if ( window_imp->completeDropRequest( gl_coord, mask, (char*)url ) )
 +				{
 +					return 0;
 +				};
 +			}
 +			break;
 +		}
 +
 +	window_imp->mCallbacks->handlePauseWatchdog(window_imp);	
 +	}
 +
 +
 +	// pass unhandled messages down to Windows
 +	return DefWindowProc(h_wnd, u_msg, w_param, l_param);
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to)
 +{
 +	S32		client_height;
 +	RECT	client_rect;
 +	LLCoordWindow window_position;
 +
 +	if (!mWindowHandle ||
 +		!GetClientRect(mWindowHandle, &client_rect) ||
 +		NULL == to)
 +	{
 +		return FALSE;
 +	}
 +
 +	to->mX = from.mX;
 +	client_height = client_rect.bottom - client_rect.top;
 +	to->mY = client_height - from.mY - 1;
 +
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to)
 +{
 +	S32		client_height;
 +	RECT	client_rect;
 +
 +	if (!mWindowHandle ||
 +		!GetClientRect(mWindowHandle, &client_rect) ||
 +		NULL == to)
 +	{
 +		return FALSE;
 +	}
 +
 +	to->mX = from.mX;
 +	client_height = client_rect.bottom - client_rect.top;
 +	to->mY = client_height - from.mY - 1;
 +
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to)
 +{	
 +	POINT mouse_point;
 +
 +	mouse_point.x = from.mX;
 +	mouse_point.y = from.mY;
 +	BOOL result = ScreenToClient(mWindowHandle, &mouse_point);
 +
 +	if (result)
 +	{
 +		to->mX = mouse_point.x;
 +		to->mY = mouse_point.y;
 +	}
 +
 +	return result;
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to)
 +{
 +	POINT mouse_point;
 +
 +	mouse_point.x = from.mX;
 +	mouse_point.y = from.mY;
 +	BOOL result = ClientToScreen(mWindowHandle, &mouse_point);
 +
 +	if (result)
 +	{
 +		to->mX = mouse_point.x;
 +		to->mY = mouse_point.y;
 +	}
 +
 +	return result;
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to)
 +{
 +	LLCoordWindow window_coord;
 +
 +	if (!mWindowHandle || (NULL == to))
 +	{
 +		return FALSE;
 +	}
 +
 +	convertCoords(from, &window_coord);
 +	convertCoords(window_coord, to);
 +	return TRUE;
 +}
 +
 +BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to)
 +{
 +	LLCoordWindow window_coord;
 +
 +	if (!mWindowHandle || (NULL == to))
 +	{
 +		return FALSE;
 +	}
 +
 +	convertCoords(from, &window_coord);
 +	convertCoords(window_coord, to);
 +	return TRUE;
 +}
 +
 +
 +BOOL LLWindowWin32::isClipboardTextAvailable()
 +{
 +	return IsClipboardFormatAvailable(CF_UNICODETEXT);
 +}
 +
 +
 +BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst)
 +{
 +	BOOL success = FALSE;
 +
 +	if (IsClipboardFormatAvailable(CF_UNICODETEXT))
 +	{
 +		if (OpenClipboard(mWindowHandle))
 +		{
 +			HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT);
 +			if (h_data)
 +			{
 +				WCHAR *utf16str = (WCHAR*) GlobalLock(h_data);
 +				if (utf16str)
 +				{
 +					dst = utf16str_to_wstring(utf16str);
 +					LLWStringUtil::removeCRLF(dst);
 +					GlobalUnlock(h_data);
 +					success = TRUE;
 +				}
 +			}
 +			CloseClipboard();
 +		}
 +	}
 +
 +	return success;
 +}
 +
 +
 +BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr)
 +{
 +	BOOL success = FALSE;
 +
 +	if (OpenClipboard(mWindowHandle))
 +	{
 +		EmptyClipboard();
 +
 +		// Provide a copy of the data in Unicode format.
 +		LLWString sanitized_string(wstr);
 +		LLWStringUtil::addCRLF(sanitized_string);
 +		llutf16string out_utf16 = wstring_to_utf16str(sanitized_string);
 +		const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR);
 +
 +		// Memory is allocated and then ownership of it is transfered to the system.
 +		HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); 
 +		if (hglobal_copy_utf16)
 +		{
 +			WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16);
 +			if (copy_utf16)
 +			{
 +				memcpy(copy_utf16, out_utf16.c_str(), size_utf16);	/* Flawfinder: ignore */
 +				GlobalUnlock(hglobal_copy_utf16);
 +
 +				if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16))
 +				{
 +					success = TRUE;
 +				}
 +			}
 +		}
 +
 +		CloseClipboard();
 +	}
 +
 +	return success;
 +}
 +
 +// Constrains the mouse to the window.
 +void LLWindowWin32::setMouseClipping( BOOL b )
 +{
 +	if( b != mIsMouseClipping )
 +	{
 +		BOOL success = FALSE;
 +
 +		if( b )
 +		{
 +			GetClipCursor( &mOldMouseClip );
 +
 +			RECT client_rect_in_screen_space;
 +			if( getClientRectInScreenSpace( &client_rect_in_screen_space ) )
 +			{
 +				success = ClipCursor( &client_rect_in_screen_space );
 +			}
 +		}
 +		else
 +		{
 +			// Must restore the old mouse clip, which may be set by another window.
 +			success = ClipCursor( &mOldMouseClip );
 +			SetRect( &mOldMouseClip, 0, 0, 0, 0 );
 +		}
 +
 +		if( success )
 +		{
 +			mIsMouseClipping = b;
 +		}
 +	}
 +}
 +
 +BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp )
 +{
 +	BOOL success = FALSE;
 +
 +	RECT client_rect;
 +	if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) )
 +	{
 +		POINT top_left;
 +		top_left.x = client_rect.left;
 +		top_left.y = client_rect.top;
 +		ClientToScreen(mWindowHandle, &top_left); 
 +
 +		POINT bottom_right;
 +		bottom_right.x = client_rect.right;
 +		bottom_right.y = client_rect.bottom;
 +		ClientToScreen(mWindowHandle, &bottom_right); 
 +
 +		SetRect( rectp,
 +			top_left.x,
 +			top_left.y,
 +			bottom_right.x,
 +			bottom_right.y );
 +
 +		success = TRUE;
 +	}
 +
 +	return success;
 +}
 +
 +void LLWindowWin32::flashIcon(F32 seconds)
 +{
 +	FLASHWINFO flash_info;
 +
 +	flash_info.cbSize = sizeof(FLASHWINFO);
 +	flash_info.hwnd = mWindowHandle;
 +	flash_info.dwFlags = FLASHW_TRAY;
 +	flash_info.uCount = UINT(seconds / ICON_FLASH_TIME);
 +	flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds
 +	FlashWindowEx(&flash_info);
 +}
 +
 +F32 LLWindowWin32::getGamma()
 +{
 +	return mCurrentGamma;
 +}
 +
 +BOOL LLWindowWin32::restoreGamma()
 +{
 +	return SetDeviceGammaRamp(mhDC, mPrevGammaRamp);
 +}
 +
 +BOOL LLWindowWin32::setGamma(const F32 gamma)
 +{
 +	mCurrentGamma = gamma;
 +
 +	LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL;
 +
 +	for ( int i = 0; i < 256; ++i )
 +	{
 +		int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f );
 +
 +		int value = mult * i;
 +
 +		if ( value > 0xffff )
 +			value = 0xffff;
 +
 +		mCurrentGammaRamp [ 0 * 256 + i ] = 
 +			mCurrentGammaRamp [ 1 * 256 + i ] = 
 +				mCurrentGammaRamp [ 2 * 256 + i ] = ( WORD )value;
 +	};
 +
 +	return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp );
 +}
 +
 +void LLWindowWin32::setFSAASamples(const U32 fsaa_samples)
 +{
 +	mFSAASamples = fsaa_samples;
 +}
 +
 +U32 LLWindowWin32::getFSAASamples()
 +{
 +	return mFSAASamples;
 +}
 +
 +LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions)
 +{
 +	if (!mSupportedResolutions)
 +	{
 +		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS];
 +		DEVMODE dev_mode;
 +
 +		mNumSupportedResolutions = 0;
 +		for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++)
 +		{
 +			if (!EnumDisplaySettings(NULL, mode_num, &dev_mode))
 +			{
 +				break;
 +			}
 +
 +			if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL &&
 +				dev_mode.dmPelsWidth >= 800 &&
 +				dev_mode.dmPelsHeight >= 600)
 +			{
 +				BOOL resolution_exists = FALSE;
 +				for(S32 i = 0; i < mNumSupportedResolutions; i++)
 +				{
 +					if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth &&
 +						mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight)
 +					{
 +						resolution_exists = TRUE;
 +					}
 +				}
 +				if (!resolution_exists)
 +				{
 +					mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth;
 +					mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight;
 +					mNumSupportedResolutions++;
 +				}
 +			}
 +		}
 +	}
 +
 +	num_resolutions = mNumSupportedResolutions;
 +	return mSupportedResolutions;
 +}
 +
 +
 +F32 LLWindowWin32::getNativeAspectRatio()
 +{
 +	if (mOverrideAspectRatio > 0.f)
 +	{
 +		return mOverrideAspectRatio;
 +	}
 +	else if (mNativeAspectRatio > 0.f)
 +	{
 +		// we grabbed this value at startup, based on the user's desktop settings
 +		return mNativeAspectRatio;
 +	}
 +	// RN: this hack presumes that the largest supported resolution is monitor-limited
 +	// and that pixels in that mode are square, therefore defining the native aspect ratio
 +	// of the monitor...this seems to work to a close approximation for most CRTs/LCDs
 +	S32 num_resolutions;
 +	LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions);
 +
 +	return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight);
 +}
 +
 +F32 LLWindowWin32::getPixelAspectRatio()
 +{
 +	F32 pixel_aspect = 1.f;
 +	if (getFullscreen())
 +	{
 +		LLCoordScreen screen_size;
 +		getSize(&screen_size);
 +		pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX;
 +	}
 +
 +	return pixel_aspect;
 +}
 +
 +// Change display resolution.  Returns true if successful.
 +// protected
 +BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh)
 +{
 +	DEVMODE dev_mode;
 +	dev_mode.dmSize = sizeof(dev_mode);
 +	BOOL success = FALSE;
 +
 +	// Don't change anything if we don't have to
 +	if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode))
 +	{
 +		if (dev_mode.dmPelsWidth        == width &&
 +			dev_mode.dmPelsHeight       == height &&
 +			dev_mode.dmBitsPerPel       == bits &&
 +			dev_mode.dmDisplayFrequency == refresh )
 +		{
 +			// ...display mode identical, do nothing
 +			return TRUE;
 +		}
 +	}
 +
 +	memset(&dev_mode, 0, sizeof(dev_mode));
 +	dev_mode.dmSize = sizeof(dev_mode);
 +	dev_mode.dmPelsWidth        = width;
 +	dev_mode.dmPelsHeight       = height;
 +	dev_mode.dmBitsPerPel       = bits;
 +	dev_mode.dmDisplayFrequency = refresh;
 +	dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
 +
 +	// CDS_FULLSCREEN indicates that this is a temporary change to the device mode.
 +	LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN);
 +
 +	success = (DISP_CHANGE_SUCCESSFUL == cds_result);
 +
 +	if (!success)
 +	{
 +		LL_WARNS("Window") << "setDisplayResolution failed, "
 +			<< width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL;
 +	}
 +
 +	return success;
 +}
 +
 +// protected
 +BOOL LLWindowWin32::setFullscreenResolution()
 +{
 +	if (mFullscreen)
 +	{
 +		return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh);
 +	}
 +	else
 +	{
 +		return FALSE;
 +	}
 +}
 +
 +// protected
 +BOOL LLWindowWin32::resetDisplayResolution()
 +{
 +	LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL;
 +
 +	LONG cds_result = ChangeDisplaySettings(NULL, 0);
 +
 +	BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result);
 +
 +	if (!success)
 +	{
 +		LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL;
 +	}
 +
 +	LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL;
 +
 +	return success;
 +}
 +
 +void LLWindowWin32::swapBuffers()
 +{
 +	SwapBuffers(mhDC);
 +}
 +
 +
 +//
 +// LLSplashScreenImp
 +//
 +LLSplashScreenWin32::LLSplashScreenWin32()
 +:	mWindow(NULL)
 +{
 +}
 +
 +LLSplashScreenWin32::~LLSplashScreenWin32()
 +{
 +}
 +
 +void LLSplashScreenWin32::showImpl()
 +{
 +	// This appears to work.  ???
 +	HINSTANCE hinst = GetModuleHandle(NULL);
 +
 +	mWindow = CreateDialog(hinst, 
 +		TEXT("SPLASHSCREEN"), 
 +		NULL,	// no parent
 +		(DLGPROC) LLSplashScreenWin32::windowProc); 
 +	ShowWindow(mWindow, SW_SHOW);
 +}
 +
 +
 +void LLSplashScreenWin32::updateImpl(const std::string& mesg)
 +{
 +	if (!mWindow) return;
 +
 +	WCHAR w_mesg[1024];
 +	mbstowcs(w_mesg, mesg.c_str(), 1024);
 +
 +	SendDlgItemMessage(mWindow,
 +		666,		// HACK: text id
 +		WM_SETTEXT,
 +		FALSE,
 +		(LPARAM)w_mesg);
 +}
 +
 +
 +void LLSplashScreenWin32::hideImpl()
 +{
 +	if (mWindow)
 +	{
 +		DestroyWindow(mWindow);
 +		mWindow = NULL; 
 +	}
 +}
 +
 +
 +// static
 +LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg,
 +											WPARAM w_param, LPARAM l_param)
 +{
 +	// Just give it to windows
 +	return DefWindowProc(h_wnd, u_msg, w_param, l_param);
 +}
 +
 +//
 +// Helper Funcs
 +//
 +
 +S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type)
 +{
 +	UINT uType;
 +
 +	switch(type)
 +	{
 +	case OSMB_OK:
 +		uType = MB_OK;
 +		break;
 +	case OSMB_OKCANCEL:
 +		uType = MB_OKCANCEL;
 +		break;
 +	case OSMB_YESNO:
 +		uType = MB_YESNO;
 +		break;
 +	default:
 +		uType = MB_OK;
 +		break;
 +	}
 +
 +	// HACK! Doesn't properly handle wide strings!
 +	int retval_win = MessageBoxA(NULL, text.c_str(), caption.c_str(), uType);
 +	S32 retval;
 +
 +	switch(retval_win)
 +	{
 +	case IDYES:
 +		retval = OSBTN_YES;
 +		break;
 +	case IDNO:
 +		retval = OSBTN_NO;
 +		break;
 +	case IDOK:
 +		retval = OSBTN_OK;
 +		break;
 +	case IDCANCEL:
 +		retval = OSBTN_CANCEL;
 +		break;
 +	default:
 +		retval = OSBTN_CANCEL;
 +		break;
 +	}
 +
 +	return retval;
 +}
 +
 +
 +void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url )
 +{
 +	bool found = false;
 +	S32 i;
 +	for (i = 0; i < gURLProtocolWhitelistCount; i++)
 +	{
 +		if (escaped_url.find(gURLProtocolWhitelist[i]) == 0)
 +		{
 +			found = true;
 +			break;
 +		}
 +	}
 +
 +	if (!found)
 +	{
 +		LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL;
 +		return;
 +	}
 +
 +	LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL;
 +
 +	// replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work
 +	// reliablly on Vista.
 +
 +	// this is madness.. no, this is..
 +	LLWString url_wstring = utf8str_to_wstring( escaped_url );
 +	llutf16string url_utf16 = wstring_to_utf16str( url_wstring );
 +
 +	// let the OS decide what to use to open the URL
 +	SHELLEXECUTEINFO sei = { sizeof( sei ) };
 +	sei.fMask = SEE_MASK_FLAG_DDEWAIT;
 +	sei.nShow = SW_SHOWNORMAL;
 +	sei.lpVerb = L"open";
 +	sei.lpFile = url_utf16.c_str();
 +	ShellExecuteEx( &sei );
 +
 +	//// TODO: LEAVING OLD CODE HERE SO I DON'T BONE OTHER MERGES
 +	//// DELETE THIS ONCE THE MERGES ARE DONE
 +
 +	// Figure out the user's default web browser
 +	// HKEY_CLASSES_ROOT\http\shell\open\command
 +	/*
 +	std::string reg_path_str = gURLProtocolWhitelistHandler[i] + "\\shell\\open\\command";
 +	WCHAR reg_path_wstr[256];
 +	mbstowcs( reg_path_wstr, reg_path_str.c_str(), LL_ARRAY_SIZE(reg_path_wstr) );
 +
 +	HKEY key;
 +	WCHAR browser_open_wstr[1024];
 +	DWORD buffer_length = 1024;
 +	RegOpenKeyEx(HKEY_CLASSES_ROOT, reg_path_wstr, 0, KEY_QUERY_VALUE, &key);
 +	RegQueryValueEx(key, NULL, NULL, NULL, (LPBYTE)browser_open_wstr, &buffer_length);
 +	RegCloseKey(key);
 +
 +	// Convert to STL string
 +	LLWString browser_open_wstring = utf16str_to_wstring(browser_open_wstr);
 +
 +	if (browser_open_wstring.length() < 2)
 +	{
 +		LL_WARNS("Window") << "Invalid browser executable in registry " << browser_open_wstring << LL_ENDL;
 +		return;
 +	}
 +
 +	// Extract the process that's supposed to be launched
 +	LLWString browser_executable;
 +	if (browser_open_wstring[0] == '"')
 +	{
 +		// executable is quoted, find the matching quote
 +		size_t quote_pos = browser_open_wstring.find('"', 1);
 +		// copy out the string including both quotes
 +		browser_executable = browser_open_wstring.substr(0, quote_pos+1);
 +	}
 +	else
 +	{
 +		// executable not quoted, find a space
 +		size_t space_pos = browser_open_wstring.find(' ', 1);
 +		browser_executable = browser_open_wstring.substr(0, space_pos);
 +	}
 +
 +	LL_DEBUGS("Window") << "Browser reg key: " << wstring_to_utf8str(browser_open_wstring) << LL_ENDL;
 +	LL_INFOS("Window") << "Browser executable: " << wstring_to_utf8str(browser_executable) << LL_ENDL;
 +
 +	// Convert URL to wide string for Windows API
 +	// Assume URL is UTF8, as can come from scripts
 +	LLWString url_wstring = utf8str_to_wstring(escaped_url);
 +	llutf16string url_utf16 = wstring_to_utf16str(url_wstring);
 +
 +	// Convert executable and path to wide string for Windows API
 +	llutf16string browser_exec_utf16 = wstring_to_utf16str(browser_executable);
 +
 +	// ShellExecute returns HINSTANCE for backwards compatiblity.
 +	// MS docs say to cast to int and compare to 32.
 +	HWND our_window = NULL;
 +	LPCWSTR directory_wstr = NULL;
 +	int retval = (int) ShellExecute(our_window, 	// Flawfinder: ignore
 +									L"open", 
 +									browser_exec_utf16.c_str(), 
 +									url_utf16.c_str(), 
 +									directory_wstr,
 +									SW_SHOWNORMAL);
 +	if (retval > 32)
 +	{
 +		LL_DEBUGS("Window") << "load_url success with " << retval << LL_ENDL;
 +	}
 +	else
 +	{
 +		LL_INFOS("Window") << "load_url failure with " << retval << LL_ENDL;
 +	}
 +	*/
 +}
 +
 +
 +BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b )
 +{
 +	BOOL retval = FALSE;
 +
 +	static CHOOSECOLOR cc;
 +	static COLORREF crCustColors[16];
 +	cc.lStructSize = sizeof(CHOOSECOLOR);
 +	cc.hwndOwner = mWindowHandle;
 +	cc.hInstance = NULL;
 +	cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f));
 +	//cc.rgbResult = RGB (0x80,0x80,0x80); 
 +	cc.lpCustColors = crCustColors;
 +	cc.Flags = CC_RGBINIT | CC_FULLOPEN;
 +	cc.lCustData = 0;
 +	cc.lpfnHook = NULL;
 +	cc.lpTemplateName = NULL;
 + 
 +	// This call is modal, so pause agent
 +	//send_agent_pause();	// this is in newview and we don't want to set up a dependency
 +	{
 +		retval = ChooseColor(&cc);
 +	}
 +	//send_agent_resume();	// this is in newview and we don't want to set up a dependency
 +
 +	*b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f;
 +
 +	*g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f;
 +	
 +	*r = ((F32)(cc.rgbResult & 0xff)) / 255.f;
 +
 +	return (retval);
 +}
 +
 +void *LLWindowWin32::getPlatformWindow()
 +{
 +	return (void*)mWindowHandle;
 +}
 +
 +void LLWindowWin32::bringToFront()
 +{
 +	BringWindowToTop(mWindowHandle);
 +}
 +
 +// set (OS) window focus back to the client
 +void LLWindowWin32::focusClient()
 +{
 +	SetFocus ( mWindowHandle );
 +}
 +
 +void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
 +{
 +	if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable())
 +	{
 +		return;
 +	}
 +
 +	if (preeditor != mPreeditor && !b)
 +	{
 +		// This condition may occur with a call to
 +		// setEnabled(BOOL) from LLTextEditor or LLLineEditor
 +		// when the control is not focused.
 +		// We need to silently ignore the case so that
 +		// the language input status of the focused control
 +		// is not disturbed.
 +		return;
 +	}
 +
 +	// Take care of old and new preeditors.
 +	if (preeditor != mPreeditor || !b)
 +	{
 +		if (sLanguageTextInputAllowed)
 +		{
 +			interruptLanguageTextInput();
 +		}
 +		mPreeditor = (b ? preeditor : NULL);
 +	}
 +
 +	sLanguageTextInputAllowed = b;
 +
 +	if ( sLanguageTextInputAllowed )
 +	{
 +		// Allowing: Restore the previous IME status, so that the user has a feeling that the previous 
 +		// text input continues naturally.  Be careful, however, the IME status is meaningful only during the user keeps 
 +		// using same Input Locale (aka Keyboard Layout).
 +		if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale)
 +		{
 +			HIMC himc = LLWinImm::getContext(mWindowHandle);
 +			LLWinImm::setOpenStatus(himc, TRUE);
 +			LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode);
 +			LLWinImm::releaseContext(mWindowHandle, himc);
 +		}
 +	}
 +	else
 +	{
 +		// Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly.
 +		// However, do it after saving the current IME  status.  We need to restore the status when
 +		//   allowing language text input again.
 +		sWinInputLocale = GetKeyboardLayout(0);
 +		sWinIMEOpened = LLWinImm::isIME(sWinInputLocale);
 +		if (sWinIMEOpened)
 +		{
 +			HIMC himc = LLWinImm::getContext(mWindowHandle);
 +			sWinIMEOpened = LLWinImm::getOpenStatus(himc);
 +			if (sWinIMEOpened)
 +			{
 +				LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode);
 +
 +				// We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's 
 +				// keyboard hooking, because Some IME reacts only on the former and some other on the latter...
 +				LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode);
 +				LLWinImm::setOpenStatus(himc, FALSE);
 +			}
 +			LLWinImm::releaseContext(mWindowHandle, himc);
 + 		}
 +	}
 +}
 +
 +void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, 
 +		CANDIDATEFORM *form)
 +{
 +	LLCoordWindow caret_coord, top_left, bottom_right;
 +	convertCoords(caret, &caret_coord);
 +	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
 +	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
 +
 +	memset(form, 0, sizeof(CANDIDATEFORM));
 +	form->dwStyle = CFS_EXCLUDE;
 +	form->ptCurrentPos.x = caret_coord.mX;
 +	form->ptCurrentPos.y = caret_coord.mY;
 +	form->rcArea.left   = top_left.mX;
 +	form->rcArea.top    = top_left.mY;
 +	form->rcArea.right  = bottom_right.mX;
 +	form->rcArea.bottom = bottom_right.mY;
 +}
 +
 +
 +// Put the IME window at the right place (near current text input).   Point coordinates should be the top of the current text line.
 +void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position )
 +{
 +	if (sLanguageTextInputAllowed && LLWinImm::isAvailable())
 +	{
 +		HIMC himc = LLWinImm::getContext(mWindowHandle);
 +
 +		LLCoordWindow win_pos;
 +		convertCoords( position, &win_pos );
 +
 +		if ( win_pos.mX >= 0 && win_pos.mY >= 0 && 
 +			(win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) )
 +		{
 +			COMPOSITIONFORM ime_form;
 +			memset( &ime_form, 0, sizeof(ime_form) );
 +			ime_form.dwStyle = CFS_POINT;
 +			ime_form.ptCurrentPos.x = win_pos.mX;
 +			ime_form.ptCurrentPos.y = win_pos.mY;
 +
 +			LLWinImm::setCompositionWindow( himc, &ime_form );
 +
 +			sWinIMEWindowPosition.set( win_pos.mX, win_pos.mY );
 +		}
 +
 +		LLWinImm::releaseContext(mWindowHandle, himc);
 +	}
 +}
 +
 +
 +void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control,
 +		IMECHARPOSITION *char_position)
 +{
 +	LLCoordScreen caret_coord, top_left, bottom_right;
 +	convertCoords(caret, &caret_coord);
 +	convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left);
 +	convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right);
 +
 +	char_position->pt.x = caret_coord.mX;
 +	char_position->pt.y = top_left.mY;	// Windows wants the coordinate of upper left corner of a character...
 +	char_position->cLineHeight = bottom_right.mY - top_left.mY;
 +	char_position->rcDocument.left   = top_left.mX;
 +	char_position->rcDocument.top    = top_left.mY;
 +	char_position->rcDocument.right  = bottom_right.mX;
 +	char_position->rcDocument.bottom = bottom_right.mY;
 +}
 +
 +void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
 +{
 +	// Our font is a list of FreeType recognized font files that may
 +	// not have a corresponding ones in Windows' fonts.  Hence, we
 +	// can't simply tell Windows which font we are using.  We will
 +	// notify a _standard_ font for a current input locale instead.
 +	// We use a hard-coded knowledge about the Windows' standard
 +	// configuration to do so...
 +
 +	memset(logfont, 0, sizeof(LOGFONT));
 +
 +	const WORD lang_id = LOWORD(GetKeyboardLayout(0));
 +	switch (PRIMARYLANGID(lang_id))
 +	{
 +	case LANG_CHINESE:
 +		// We need to identify one of two Chinese fonts.
 +		switch (SUBLANGID(lang_id))
 +		{
 +		case SUBLANG_CHINESE_SIMPLIFIED:
 +		case SUBLANG_CHINESE_SINGAPORE:
 +			logfont->lfCharSet = GB2312_CHARSET;
 +			lstrcpy(logfont->lfFaceName, TEXT("SimHei"));
 +			break;
 +		case SUBLANG_CHINESE_TRADITIONAL:
 +		case SUBLANG_CHINESE_HONGKONG:
 +		case SUBLANG_CHINESE_MACAU:
 +		default:
 +			logfont->lfCharSet = CHINESEBIG5_CHARSET;
 +			lstrcpy(logfont->lfFaceName, TEXT("MingLiU"));
 +			break;			
 +		}
 +		break;
 +	case LANG_JAPANESE:
 +		logfont->lfCharSet = SHIFTJIS_CHARSET;
 +		lstrcpy(logfont->lfFaceName, TEXT("MS Gothic"));
 +		break;		
 +	case LANG_KOREAN:
 +		logfont->lfCharSet = HANGUL_CHARSET;
 +		lstrcpy(logfont->lfFaceName, TEXT("Gulim"));
 +		break;
 +	default:
 +		logfont->lfCharSet = ANSI_CHARSET;
 +		lstrcpy(logfont->lfFaceName, TEXT("Tahoma"));
 +		break;
 +	}
 +							
 +	logfont->lfHeight = mPreeditor->getPreeditFontSize();
 +	logfont->lfWeight = FW_NORMAL;
 +}	
 +
 +U32 LLWindowWin32::fillReconvertString(const LLWString &text,
 +	S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string)
 +{
 +	const llutf16string text_utf16 = wstring_to_utf16str(text);
 +	const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR);
 +	if (reconvert_string && reconvert_string->dwSize >= required_size)
 +	{
 +		const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus);
 +		const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length);
 +
 +		reconvert_string->dwVersion = 0;
 +		reconvert_string->dwStrLen = text_utf16.length();
 +		reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING);
 +		reconvert_string->dwCompStrLen = focus_utf16_length;
 +		reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR);
 +		reconvert_string->dwTargetStrLen = 0;
 +		reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR);
 +
 +		const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING));
 +		memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR));
 +	}
 +	return required_size;
 +}
 +
 +void LLWindowWin32::updateLanguageTextInputArea()
 +{
 +	if (!mPreeditor || !LLWinImm::isAvailable())
 +	{
 +		return;
 +	}
 +
 +	LLCoordGL caret_coord;
 +	LLRect preedit_bounds;
 +	if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL))
 +	{
 +		mLanguageTextInputPointGL = caret_coord;
 +		mLanguageTextInputAreaGL = preedit_bounds;
 +
 +		CANDIDATEFORM candidate_form;
 +		fillCandidateForm(caret_coord, preedit_bounds, &candidate_form);
 +
 +		HIMC himc = LLWinImm::getContext(mWindowHandle);
 +		// Win32 document says there may be up to 4 candidate windows.
 +		// This magic number 4 appears only in the document, and
 +		// there are no constant/macro for the value...
 +		for (int i = 3; i >= 0; --i)
 +		{
 +			candidate_form.dwIndex = i;
 +			LLWinImm::setCandidateWindow(himc, &candidate_form);
 +		}
 +		LLWinImm::releaseContext(mWindowHandle, himc);
 +	}
 +}
 +
 +void LLWindowWin32::interruptLanguageTextInput()
 +{
 +	if (mPreeditor)
 +	{
 +		if (LLWinImm::isAvailable())
 +		{
 +			HIMC himc = LLWinImm::getContext(mWindowHandle);
 +			LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
 +			LLWinImm::releaseContext(mWindowHandle, himc);
 +		}
 +
 +		// Win32 document says there will be no composition string
 +		// after NI_COMPOSITIONSTR returns.  The following call to
 +		// resetPreedit should be a NOP unless IME goes mad...
 +		mPreeditor->resetPreedit();
 +	}
 +}
 +
 +void LLWindowWin32::handleStartCompositionMessage()
 +{
 +	// Let IME know the font to use in feedback UI.
 +	LOGFONT logfont;
 +	fillCompositionLogfont(&logfont);
 +	HIMC himc = LLWinImm::getContext(mWindowHandle);
 +	LLWinImm::setCompositionFont(himc, &logfont);
 +	LLWinImm::releaseContext(mWindowHandle, himc);
 +}
 +
 +// Handle WM_IME_COMPOSITION message.
 +
 +void LLWindowWin32::handleCompositionMessage(const U32 indexes)
 +{
 +	BOOL needs_update = FALSE;
 +	LLWString result_string;
 +	LLWString preedit_string;
 +	S32 preedit_string_utf16_length = 0;
 +	LLPreeditor::segment_lengths_t preedit_segment_lengths;
 +	LLPreeditor::standouts_t preedit_standouts;
 +
 +	// Step I: Receive details of preedits from IME.
 +
 +	HIMC himc = LLWinImm::getContext(mWindowHandle);
 +
 +	if (indexes & GCS_RESULTSTR)
 +	{
 +		LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0);
 +		if (size >= 0)
 +		{
 +			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
 +			size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size);
 +			if (size > 0)
 +			{
 +				result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
 +			}
 +			delete[] data;
 +			needs_update = TRUE;
 +		}
 +	}
 +	
 +	if (indexes & GCS_COMPSTR)
 +	{
 +		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0);
 +		if (size >= 0)
 +		{
 +			const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1];
 +			size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size);
 +			if (size > 0)
 +			{
 +				preedit_string_utf16_length = size / sizeof(WCHAR);
 +				preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR)));
 +			}
 +			delete[] data;
 +			needs_update = TRUE;
 +		}
 +	}
 +
 +	if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0)
 +	{
 +		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0);
 +		if (size > 0)
 +		{
 +			const LPDWORD data = new DWORD[size / sizeof(DWORD)];
 +			size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size);
 +			if (size >= sizeof(DWORD) * 2
 +				&& data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length)
 +			{
 +				preedit_segment_lengths.resize(size / sizeof(DWORD) - 1);
 +				S32 offset = 0;
 +				for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
 +				{
 +					const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]);
 +					preedit_segment_lengths[i] = length;
 +					offset += length;
 +				}
 +			}
 +			delete[] data;
 +		}
 +	}
 +
 +	if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1)
 +	{
 +		LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0);
 +		if (size > 0)
 +		{
 +			const LPBYTE data = new BYTE[size / sizeof(BYTE)];
 +			size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size);
 +			if (size == preedit_string_utf16_length)
 +			{
 +				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
 +				S32 offset = 0;
 +				for (U32 i = 0; i < preedit_segment_lengths.size(); i++)
 +				{
 +					if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset])
 +					{
 +						preedit_standouts[i] = TRUE;
 +					}
 +					offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]);
 +				}
 +			}
 +			delete[] data;
 +		}
 +	}
 +
 +	S32 caret_position = preedit_string.length();
 +	if (indexes & GCS_CURSORPOS)
 +	{
 +		const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0);
 +		if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length)
 +		{
 +			caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16);
 +		}
 +	}
 +
 +	if (indexes == 0)
 +	{
 +		// I'm not sure this condition really happens, but
 +		// Windows SDK document says it is an indication
 +		// of "reset everything."
 +		needs_update = TRUE;
 +	}
 +
 +	LLWinImm::releaseContext(mWindowHandle, himc);
 +
 +	// Step II: Update the active preeditor.
 +
 +	if (needs_update)
 +	{
 +		mPreeditor->resetPreedit();
 +
 +		if (result_string.length() > 0)
 +		{
 +			for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++)
 +			{
 +				mPreeditor->handleUnicodeCharHere(*i);
 +			}
 +		}
 +
 +		if (preedit_string.length() == 0)
 + 		{
 +			preedit_segment_lengths.clear();
 +			preedit_standouts.clear();
 +		}
 +		else
 +		{
 +			if (preedit_segment_lengths.size() == 0)
 +			{
 +				preedit_segment_lengths.assign(1, preedit_string.length());
 +			}
 +			if (preedit_standouts.size() == 0)
 +			{
 +				preedit_standouts.assign(preedit_segment_lengths.size(), FALSE);
 +			}
 +		}
 +		mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
 +
 +		// Some IME doesn't query char position after WM_IME_COMPOSITION,
 +		// so we need to update them actively.
 +		updateLanguageTextInputArea();
 +	}
 +}
 +
 +// Given a text and a focus range, find_context finds and returns a
 +// surrounding context of the focused subtext.  A variable pointed
 +// to by offset receives the offset in llwchars of the beginning of
 +// the returned context string in the given wtext.
 +
 +static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset)
 +{
 +	static const S32 CONTEXT_EXCESS = 30;	// This value is by experiences.
 +
 +	const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS);
 +	S32 end = focus + focus_length;
 +	while (end < e && '\n' != wtext[end])
 +	{
 +		end++;
 +	}
 +
 +	const S32 s = llmax(0, focus - CONTEXT_EXCESS);
 +	S32 start = focus;
 +	while (start > s && '\n' != wtext[start - 1])
 +	{
 +		--start;
 +	}
 +
 +	*offset = start;
 +	return wtext.substr(start, end - start);
 +}
 +
 +// final stage of handling drop requests - both from WM_DROPFILES message
 +// for files and via IDropTarget interface requests.
 +BOOL LLWindowWin32::completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url )
 +{
 +	if ( mCallbacks->handleDrop( this, gl_coord, mask, url ) )
 +	{
 +		return TRUE;
 +	};
 +
 +	return FALSE;
 +};
 +
 +// Handle WM_IME_REQUEST message.
 +// If it handled the message, returns TRUE.  Otherwise, FALSE.
 +// When it handled the message, the value to be returned from
 +// the Window Procedure is set to *result.
 +
 +BOOL LLWindowWin32::handleImeRequests(U32 request, U32 param, LRESULT *result)
 +{
 +	if ( mPreeditor )
 +	{
 +		switch (request)
 +		{
 +			case IMR_CANDIDATEWINDOW:		// http://msdn2.microsoft.com/en-us/library/ms776080.aspx
 +			{
 +				LLCoordGL caret_coord;
 +				LLRect preedit_bounds;
 +				mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL);
 +				
 +				CANDIDATEFORM *const form = (CANDIDATEFORM *)param;
 +				DWORD const dwIndex = form->dwIndex;
 +				fillCandidateForm(caret_coord, preedit_bounds, form);
 +				form->dwIndex = dwIndex;
 +
 +				*result = 1;
 +				return TRUE;
 +			}
 +			case IMR_QUERYCHARPOSITION:
 +			{
 +				IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param;
 +
 +				// char_position->dwCharPos counts in number of
 +				// WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the
 +				// number to getPreeditLocation.  
 +
 +				const LLWString & wtext = mPreeditor->getPreeditString();
 +				S32 preedit, preedit_length;
 +				mPreeditor->getPreeditRange(&preedit, &preedit_length);
 +				LLCoordGL caret_coord;
 +				LLRect preedit_bounds, text_control;
 +				const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos);
 +
 +				if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control))
 +				{
 +					LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL;
 +					return FALSE;
 +				}
 +				fillCharPosition(caret_coord, preedit_bounds, text_control, char_position);
 +
 +				*result = 1;
 +				return TRUE;
 +			}
 +			case IMR_COMPOSITIONFONT:
 +			{
 +				fillCompositionLogfont((LOGFONT *)param);
 +
 +				*result = 1;
 +				return TRUE;
 +			}
 +			case IMR_RECONVERTSTRING:
 +			{
 +				mPreeditor->resetPreedit();
 +				const LLWString & wtext = mPreeditor->getPreeditString();
 +				S32 select, select_length;
 +				mPreeditor->getSelectionRange(&select, &select_length);
 +
 +				S32 context_offset;
 +				const LLWString context = find_context(wtext, select, select_length, &context_offset);
 +
 +				RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param;
 +				const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string);
 +				if (reconvert_string)
 +				{
 +					if (select_length == 0)
 +					{
 +						// Let the IME to decide the reconversion range, and
 +						// adjust the reconvert_string structure accordingly.
 +						HIMC himc = LLWinImm::getContext(mWindowHandle);
 +						const BOOL adjusted = LLWinImm::setCompositionString(himc,
 +									SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0);
 +						LLWinImm::releaseContext(mWindowHandle, himc);
 +						if (adjusted)
 +						{
 +							const llutf16string & text_utf16 = wstring_to_utf16str(context);
 +							const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR);
 +							const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen;
 +							select = utf16str_wstring_length(text_utf16, new_preedit_start);
 +							select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select;
 +							select += context_offset;
 +						}
 +					}
 +					mPreeditor->markAsPreedit(select, select_length);
 +				}
 +
 +				*result = size;
 +				return TRUE;
 +			}
 +			case IMR_CONFIRMRECONVERTSTRING:
 +			{
 +				*result = FALSE;
 +				return TRUE;
 +			}
 +			case IMR_DOCUMENTFEED:
 +			{
 +				const LLWString & wtext = mPreeditor->getPreeditString();
 +				S32 preedit, preedit_length;
 +				mPreeditor->getPreeditRange(&preedit, &preedit_length);
 +				
 +				S32 context_offset;
 +				LLWString context = find_context(wtext, preedit, preedit_length, &context_offset);
 +				preedit -= context_offset;
 +				if (preedit_length)
 +				{
 +					// IMR_DOCUMENTFEED may be called when we have an active preedit.
 +					// We should pass the context string *excluding* the preedit string.
 +					// Otherwise, some IME are confused.
 +					context.erase(preedit, preedit_length);
 +				}
 +				
 +				RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param;
 +				*result = fillReconvertString(context, preedit, 0, reconvert_string);
 +				return TRUE;
 +			}
 +			default:
 +				return FALSE;
 +		}
 +	}
 +
 +	return FALSE;
 +}
 +
 +//static
 +std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList()
 +{
 +	// Fonts previously in getFontListSans() have moved to fonts.xml.
 +	return std::vector<std::string>();
 +}
 +
 +
 +#endif // LL_WINDOWS
 diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index e14324c9f1..1382cf93a2 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -39,6 +39,7 @@  #include <windows.h>  #include "llwindow.h" +#include "lldragdropwin32.h"  // Hack for async host by name  #define LL_WM_HOST_RESOLVED      (WM_APP + 1) @@ -112,6 +113,8 @@ public:  	/*virtual*/ void interruptLanguageTextInput();  	/*virtual*/ void spawnWebBrowser(const std::string& escaped_url); +	BOOL completeDropRequest( const LLCoordGL gl_coord, const MASK mask, const std::string url ); +  	static std::vector<std::string> getDynamicFallbackFontList();  protected: @@ -206,6 +209,8 @@ protected:  	LLPreeditor		*mPreeditor; +	LLDragDropWin32* mDragDrop; +  	friend class LLWindowManager;  }; diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp index 0b7092fad6..6acac07423 100644 --- a/indra/media_plugins/base/media_plugin_base.cpp +++ b/indra/media_plugins/base/media_plugin_base.cpp @@ -64,6 +64,7 @@ std::string MediaPluginBase::statusString()  		case STATUS_ERROR:		result = "error";		break;  		case STATUS_PLAYING:	result = "playing";		break;  		case STATUS_PAUSED:		result = "paused";		break; +		case STATUS_DONE:		result = "done";		break;  		default:  			// keep the empty string  		break; diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h index 8f600cb8d6..f1e96335f9 100644 --- a/indra/media_plugins/base/media_plugin_base.h +++ b/indra/media_plugins/base/media_plugin_base.h @@ -56,6 +56,7 @@ protected:  		STATUS_ERROR,  		STATUS_PLAYING,  		STATUS_PAUSED, +		STATUS_DONE  	} EStatus;  	class SharedSegmentInfo diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp index c9ee1c8ac7..fb6d5b2905 100644 --- a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -420,7 +420,7 @@ private:  	{
  		if ( mCommand == COMMAND_PLAY )
  		{
 -			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING )
 +			if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING || mStatus == STATUS_DONE )
  			{
  				long state = GetMovieLoadState( mMovieHandle );
 @@ -446,7 +446,7 @@ private:  		else
  		if ( mCommand == COMMAND_STOP )
  		{
 -			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED )
 +			if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED || mStatus == STATUS_DONE )
  			{
  				if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK )
  				{
 @@ -547,12 +547,12 @@ private:  		// see if title arrived and if so, update member variable with contents
  		checkTitle();
 -
 -		// special code for looping - need to rewind at the end of the movie
 -		if ( mIsLooping )
 +		
 +		// QT call to see if we are at the end - can't do with controller
 +		if ( IsMovieDone( mMovieHandle ) )
  		{
 -			// QT call to see if we are at the end - can't do with controller
 -			if ( IsMovieDone( mMovieHandle ) )
 +			// special code for looping - need to rewind at the end of the movie
 +			if ( mIsLooping )
  			{
  				// go back to start
  				rewind();
 @@ -565,8 +565,16 @@ private:  					// set the volume
  					MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume );
  				};
 -			};
 -		};
 +			}
 +			else
 +			{
 +				if(mStatus == STATUS_PLAYING)
 +				{
 +					setStatus(STATUS_DONE);
 +				}
 +			}
 +		}
 +
  	};
  	int getDataWidth() const
 diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dd3937a6ef..a7681e4a1d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -63,13 +63,13 @@ include_directories(      )  set(viewer_SOURCE_FILES -    llaccordionctrltab.cpp      llaccordionctrl.cpp +    llaccordionctrltab.cpp      llagent.cpp -    llagentlistener.cpp      llagentaccess.cpp      llagentdata.cpp      llagentlanguage.cpp +    llagentlistener.cpp      llagentpicksinfo.cpp      llagentpilot.cpp      llagentui.cpp @@ -78,8 +78,8 @@ set(viewer_SOURCE_FILES      llappearancemgr.cpp      llappviewer.cpp      llappviewerlistener.cpp -    llassetuploadresponders.cpp      llassetuploadqueue.cpp +    llassetuploadresponders.cpp      llaudiosourcevo.cpp      llavataractions.cpp      llavatariconctrl.cpp @@ -95,8 +95,8 @@ set(viewer_SOURCE_FILES      llcaphttpsender.cpp      llchannelmanager.cpp      llchatbar.cpp -    llchatitemscontainerctrl.cpp      llchathistory.cpp +    llchatitemscontainerctrl.cpp      llchatmsgbox.cpp      llchiclet.cpp      llclassifiedinfo.cpp @@ -116,10 +116,10 @@ set(viewer_SOURCE_FILES      lldirpicker.cpp      lldndbutton.cpp      lldrawable.cpp +    lldrawpool.cpp      lldrawpoolalpha.cpp      lldrawpoolavatar.cpp      lldrawpoolbump.cpp -    lldrawpool.cpp      lldrawpoolground.cpp      lldrawpoolsimple.cpp      lldrawpoolsky.cpp @@ -151,8 +151,8 @@ set(viewer_SOURCE_FILES      llfloaterbuildoptions.cpp      llfloaterbulkpermission.cpp      llfloaterbump.cpp -    llfloaterbuycontents.cpp      llfloaterbuy.cpp +    llfloaterbuycontents.cpp      llfloaterbuycurrency.cpp      llfloaterbuyland.cpp      llfloatercall.cpp @@ -163,8 +163,8 @@ set(viewer_SOURCE_FILES      llfloatercustomize.cpp      llfloaterdaycycle.cpp      llfloaterenvsettings.cpp -    llfloaterfriends.cpp      llfloaterfonttest.cpp +    llfloaterfriends.cpp      llfloatergesture.cpp      llfloatergodtools.cpp      llfloatergroupinvite.cpp @@ -172,8 +172,6 @@ set(viewer_SOURCE_FILES      llfloaterhandler.cpp      llfloaterhardwaresettings.cpp      llfloaterhelpbrowser.cpp -    llfloatermediabrowser.cpp -    llfloatermediasettings.cpp      llfloaterhud.cpp      llfloaterimagepreview.cpp      llfloaterinspect.cpp @@ -183,6 +181,8 @@ set(viewer_SOURCE_FILES      llfloaterland.cpp      llfloaterlandholdings.cpp      llfloatermap.cpp +    llfloatermediabrowser.cpp +    llfloatermediasettings.cpp      llfloatermemleak.cpp      llfloaternamedesc.cpp      llfloaternotificationsconsole.cpp @@ -227,8 +227,8 @@ set(viewer_SOURCE_FILES      llgroupmgr.cpp      llgroupnotify.cpp      llhomelocationresponder.cpp -    llhudeffectbeam.cpp      llhudeffect.cpp +    llhudeffectbeam.cpp      llhudeffectlookat.cpp      llhudeffectpointat.cpp      llhudeffecttrail.cpp @@ -238,11 +238,11 @@ set(viewer_SOURCE_FILES      llhudrender.cpp      llhudtext.cpp      llhudview.cpp +    llimcontrolpanel.cpp      llimfloater.cpp      llimhandler.cpp      llimpanel.cpp      llimview.cpp -    llimcontrolpanel.cpp      llinspect.cpp      llinspectavatar.cpp      llinspectgroup.cpp @@ -260,7 +260,6 @@ set(viewer_SOURCE_FILES      lllocaltextureobject.cpp      lllocationhistory.cpp      lllocationinputctrl.cpp -    llurllineeditorctrl.cpp      lllogchat.cpp      llloginhandler.cpp      lllogininstance.cpp @@ -312,8 +311,8 @@ set(viewer_SOURCE_FILES      llpanelgrouplandmoney.cpp      llpanelgroupnotices.cpp      llpanelgrouproles.cpp -    llpanelinventory.cpp      llpanelimcontrolpanel.cpp +    llpanelinventory.cpp      llpanelland.cpp      llpanellandaudio.cpp      llpanellandmarks.cpp @@ -322,11 +321,10 @@ set(viewer_SOURCE_FILES      llpanellookinfo.cpp      llpanellooks.cpp      llpanelmedia.cpp -    llpanelmediahud.cpp -    llpanelmeprofile.cpp      llpanelmediasettingsgeneral.cpp -    llpanelmediasettingssecurity.cpp      llpanelmediasettingspermissions.cpp +    llpanelmediasettingssecurity.cpp +    llpanelmeprofile.cpp      llpanelobject.cpp      llpanelpeople.cpp      llpanelpeoplemenus.cpp @@ -335,11 +333,12 @@ set(viewer_SOURCE_FILES      llpanelpicks.cpp      llpanelplace.cpp      llpanelplaceinfo.cpp -    llpanelshower.cpp      llpanelplaces.cpp      llpanelplacestab.cpp +    llpanelprimmediacontrols.cpp      llpanelprofile.cpp      llpanelprofileview.cpp +    llpanelshower.cpp      llpanelteleporthistory.cpp      llpanelvolume.cpp      llparcelselection.cpp @@ -348,8 +347,8 @@ set(viewer_SOURCE_FILES      llplacesinventorybridge.cpp      llpolymesh.cpp      llpolymorph.cpp -    llpreviewanim.cpp      llpreview.cpp +    llpreviewanim.cpp      llpreviewgesture.cpp      llpreviewnotecard.cpp      llpreviewscript.cpp @@ -371,6 +370,7 @@ set(viewer_SOURCE_FILES      llsky.cpp      llslurl.cpp      llspatialpartition.cpp +    llspeakers.cpp      llsplitbutton.cpp      llsprite.cpp      llstartup.cpp @@ -397,10 +397,10 @@ set(viewer_SOURCE_FILES      lltoastimpanel.cpp      lltoastnotifypanel.cpp      lltoastpanel.cpp +    lltool.cpp      lltoolbar.cpp      lltoolbrush.cpp      lltoolcomp.cpp -    lltool.cpp      lltooldraganddrop.cpp      lltoolface.cpp      lltoolfocus.cpp @@ -424,6 +424,7 @@ set(viewer_SOURCE_FILES      llurl.cpp      llurldispatcher.cpp      llurlhistory.cpp +    llurllineeditorctrl.cpp      llurlsimstring.cpp      llurlwhitelist.cpp      llvectorperfoptions.cpp @@ -440,18 +441,18 @@ set(viewer_SOURCE_FILES      llviewerhelp.cpp      llviewerhelputil.cpp      llviewerinventory.cpp -    llviewerjointattachment.cpp      llviewerjoint.cpp +    llviewerjointattachment.cpp      llviewerjointmesh.cpp -    llviewerjointmesh_sse2.cpp      llviewerjointmesh_sse.cpp +    llviewerjointmesh_sse2.cpp      llviewerjointmesh_vec.cpp      llviewerjoystick.cpp      llviewerkeyboard.cpp      llviewerlayer.cpp      llviewermedia.cpp -    llviewermediafocus.cpp      llviewermedia_streamingaudio.cpp +    llviewermediafocus.cpp      llviewermenu.cpp      llviewermenufile.cpp      llviewermessage.cpp @@ -484,10 +485,11 @@ set(viewer_SOURCE_FILES      llvoclouds.cpp      llvograss.cpp      llvoground.cpp +    llvoicechannel.cpp      llvoiceclient.cpp +    llvoicecontrolpanel.cpp      llvoiceremotectrl.cpp      llvoicevisualizer.cpp -    llvoicecontrolpanel.cpp      llvoinventorylistener.cpp      llvopartgroup.cpp      llvosky.cpp @@ -538,25 +540,25 @@ endif (LINUX)  set(viewer_HEADER_FILES      CMakeLists.txt      ViewerInstall.cmake -    llaccordionctrltab.h      llaccordionctrl.h +    llaccordionctrltab.h      llagent.h -    llagentlistener.h      llagentaccess.h      llagentdata.h      llagentlanguage.h +    llagentlistener.h      llagentpicksinfo.h      llagentpilot.h      llagentui.h      llagentwearables.h      llanimstatelabels.h      llappearance.h +    llappearancemgr.h      llappviewer.h      llappviewerlistener.h -    llassetuploadresponders.h      llassetuploadqueue.h +    llassetuploadresponders.h      llaudiosourcevo.h -    llappearancemgr.h      llavataractions.h      llavatariconctrl.h      llavatarlist.h @@ -572,8 +574,8 @@ set(viewer_HEADER_FILES      llcaphttpsender.h      llchannelmanager.h      llchatbar.h -    llchatitemscontainerctrl.h      llchathistory.h +    llchatitemscontainerctrl.h      llchatmsgbox.h      llchiclet.h      llclassifiedinfo.h @@ -650,8 +652,6 @@ set(viewer_HEADER_FILES      llfloaterhandler.h      llfloaterhardwaresettings.h      llfloaterhelpbrowser.h -    llfloatermediabrowser.h -    llfloatermediasettings.h      llfloaterhud.h      llfloaterimagepreview.h      llfloaterinspect.h @@ -661,16 +661,18 @@ set(viewer_HEADER_FILES      llfloaterland.h      llfloaterlandholdings.h      llfloatermap.h +    llfloatermediabrowser.h +    llfloatermediasettings.h      llfloatermemleak.h      llfloaternamedesc.h      llfloaternotificationsconsole.h      llfloateropenobject.h      llfloaterparcel.h      llfloaterpay.h +    llfloaterperms.h      llfloaterpostcard.h      llfloaterpostprocess.h      llfloaterpreference.h -    llfloaterperms.h      llfloaterproperties.h      llfloaterregioninfo.h      llfloaterreporter.h @@ -716,12 +718,12 @@ set(viewer_HEADER_FILES      llhudrender.h      llhudtext.h      llhudview.h +    llimcontrolpanel.h      llimfloater.h      llimpanel.h      llimview.h -    llimcontrolpanel.h -    llinspectavatar.h      llinspect.h +    llinspectavatar.h      llinspectgroup.h      llinspectobject.h      llinventorybridge.h @@ -738,7 +740,6 @@ set(viewer_HEADER_FILES      lllocaltextureobject.h      lllocationhistory.h      lllocationinputctrl.h -    llurllineeditorctrl.h      lllogchat.h      llloginhandler.h      lllogininstance.h @@ -747,6 +748,7 @@ set(viewer_HEADER_FILES      llmanipscale.h      llmaniptranslate.h      llmapresponders.h +    llmediactrl.h      llmediadataclient.h      llmediaremotectrl.h      llmemoryview.h @@ -786,8 +788,8 @@ set(viewer_HEADER_FILES      llpanelgrouplandmoney.h      llpanelgroupnotices.h      llpanelgrouproles.h -    llpanelinventory.h      llpanelimcontrolpanel.h +    llpanelinventory.h      llpanelland.h      llpanellandaudio.h      llpanellandmarks.h @@ -796,11 +798,10 @@ set(viewer_HEADER_FILES      llpanellookinfo.h      llpanellooks.h      llpanelmedia.h -    llpanelmediahud.h -    llpanelmeprofile.h      llpanelmediasettingsgeneral.h -    llpanelmediasettingssecurity.h      llpanelmediasettingspermissions.h +    llpanelmediasettingssecurity.h +    llpanelmeprofile.h      llpanelobject.h      llpanelpeople.h      llpanelpeoplemenus.h @@ -809,11 +810,12 @@ set(viewer_HEADER_FILES      llpanelpicks.h      llpanelplace.h      llpanelplaceinfo.h -    llpanelshower.h      llpanelplaces.h      llpanelplacestab.h +    llpanelprimmediacontrols.h      llpanelprofile.h      llpanelprofileview.h +    llpanelshower.h      llpanelteleporthistory.h      llpanelvolume.h      llparcelselection.h @@ -836,9 +838,9 @@ set(viewer_HEADER_FILES      llremoteparcelrequest.h      llresourcedata.h      llrootview.h +    llsavedsettingsglue.h      llscreenchannel.h      llscrollingpanelparam.h -    llsavedsettingsglue.h      llsearchcombobox.h      llsearchhistory.h      llselectmgr.h @@ -847,6 +849,7 @@ set(viewer_HEADER_FILES      llsky.h      llslurl.h      llspatialpartition.h +    llspeakers.h      llsplitbutton.h      llsprite.h      llstartup.h @@ -902,6 +905,7 @@ set(viewer_HEADER_FILES      llurl.h      llurldispatcher.h      llurlhistory.h +    llurllineeditorctrl.h      llurlsimstring.h      llurlwhitelist.h      llvectorperfoptions.h @@ -925,8 +929,8 @@ set(viewer_HEADER_FILES      llviewerkeyboard.h      llviewerlayer.h      llviewermedia.h -    llviewermediaobserver.h      llviewermediafocus.h +    llviewermediaobserver.h      llviewermenu.h      llviewermenufile.h      llviewermessage.h @@ -960,10 +964,11 @@ set(viewer_HEADER_FILES      llvoclouds.h      llvograss.h      llvoground.h +    llvoicechannel.h      llvoiceclient.h +    llvoicecontrolpanel.h      llvoiceremotectrl.h      llvoicevisualizer.h -    llvoicecontrolpanel.h      llvoinventorylistener.h      llvopartgroup.h      llvosky.h @@ -981,7 +986,6 @@ set(viewer_HEADER_FILES      llwearabledictionary.h      llwearablelist.h      llweb.h -    llmediactrl.h      llwind.h      llwindebug.h      llwlanimator.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 3682d48577..568e8deb59 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5327,6 +5327,17 @@        <key>Value</key>  	  <integer>13</integer>      </map> +	<key>PrimMediaDragNDrop</key> +	<map> +		<key>Comment</key> +		<string>Enable drag and drop</string> +		<key>Persist</key> +		<integer>1</integer> +		<key>Type</key> +		<string>Boolean</string> +		<key>Value</key> +		<integer>1</integer> +	</map>      <key>PrimMediaMaxRetries</key>      <map>        <key>Comment</key> @@ -7742,6 +7753,39 @@        <key>Value</key>        <integer>1</integer>      </map> +    <key>FriendsListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide online and all friends icons in the friend list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>NearbyListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide people icons in nearby list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map> +    <key>RecentListShowIcons</key> +    <map> +      <key>Comment</key> +      <string>Show/hide people icons in recent list</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map>      <key>FriendsSortOrder</key>      <map>        <key>Comment</key> @@ -10460,6 +10504,17 @@        <key>Value</key>        <real>90.0</real>      </map> +    <key>YouAreHereDistance</key> +    <map> +      <key>Comment</key> +      <string>Radius of distance for banner that indicates if the resident is "on" the Place.(meters from avatar to requested place)</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>10.0</real> +    </map>      <key>YieldTime</key>      <map>        <key>Comment</key> diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml index f3bfa37cea..c43ba27984 100644 --- a/indra/newview/character/avatar_lad.xml +++ b/indra/newview/character/avatar_lad.xml @@ -5589,6 +5589,13 @@      </layer>      <layer +       name="hair texture alpha layer" +       visibility_mask="TRUE"> +      <texture +         local_texture="hair_grain" /> +    </layer> + +    <layer         name="hair alpha"         visibility_mask="TRUE">        <texture diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index f62606cc50..75a72e5b17 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -42,7 +42,7 @@  #include "lldrawable.h"  #include "llfirstuse.h"  #include "llfloaterreg.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  #include "llfloatercamera.h"  #include "llfloatercustomize.h" @@ -5391,12 +5391,6 @@ void update_group_floaters(const LLUUID& group_id)  	//*TODO Implement group update for Profile View   	// still actual as of July 31, 2009 (DZ) -	if (gIMMgr) -	{ -		// update the talk view -		gIMMgr->refresh(); -	} -  	gAgent.fireEvent(new LLOldEvents::LLEvent(&gAgent, "new group"), "");  } diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp index 1a69f1d975..09f7c49f23 100644 --- a/indra/newview/llagentui.cpp +++ b/indra/newview/llagentui.cpp @@ -89,6 +89,11 @@ std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/)  	return slurl;  } +//static +BOOL LLAgentUI::checkAgentDistance(const LLVector3& pole, F32 radius) +{ +	return  (gAgent.getPositionAgent() - pole).length() < radius; +}  BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region)  {  	LLViewerRegion* region = gAgent.getRegion(); diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h index 47ecb04547..c7aafb71e7 100644 --- a/indra/newview/llagentui.h +++ b/indra/newview/llagentui.h @@ -52,6 +52,11 @@ public:  	static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK);  	//build location string using a region position of the avatar.   	static BOOL buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region); +	/** +	 * @brief Check whether  the agent is in neighborhood of the pole  Within same region +	 * @return true if the agent is in neighborhood. +	 */ +	static BOOL checkAgentDistance(const LLVector3& local_pole, F32 radius);  };  #endif //LLAGENTUI_H diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e184d99ffc..06c9171d67 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -49,7 +49,6 @@  #include "llviewerstats.h"  #include "llmd5.h"  #include "llpumpio.h" -#include "llimpanel.h"  #include "llmimetypes.h"  #include "llslurl.h"  #include "llstartup.h" @@ -76,6 +75,7 @@  #include "llteleporthistory.h"  #include "lllocationhistory.h"  #include "llfasttimerview.h" +#include "llvoicechannel.h"  #include "llweb.h"  #include "llsecondlifeurls.h" diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h index 426fcec514..65b5c86ed5 100644 --- a/indra/newview/llavatariconctrl.h +++ b/indra/newview/llavatariconctrl.h @@ -103,6 +103,8 @@ public:  	const std::string&	getFirstName() const { return mFirstName; }  	const std::string&	getLastName() const { return mLastName; } +	void setDrawTooltip(bool value) { mDrawTooltip = value;} +  protected:  	LLUUID				mAvatarId;  	std::string			mFirstName; diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 3a07c6e5ef..e93d0dfa50 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -38,6 +38,7 @@  #include "llcallingcard.h" // for LLAvatarTracker  #include "llcachename.h"  #include "llvoiceclient.h" +#include "llviewercontrol.h"	// for gSavedSettings  static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); @@ -45,6 +46,21 @@ static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list");  // Used to limit time spent for avatar list update per frame.  static const unsigned ADD_LIMIT = 50; +void LLAvatarList::toggleIcons() +{ +	// Save the new value for new items to use. +	mShowIcons = !mShowIcons; +	gSavedSettings.setBOOL(mIconParamName, mShowIcons); +	 +	// Show/hide icons for all existing items. +	std::vector<LLPanel*> items; +	getItems(items); +	for( std::vector<LLPanel*>::const_iterator it = items.begin(); it != items.end(); it++) +	{ +		static_cast<LLAvatarListItem*>(*it)->setAvatarIconVisible(mShowIcons); +	} +} +  static bool findInsensitive(std::string haystack, const std::string& needle_upper)  {      LLStringUtil::toUpper(haystack); @@ -73,13 +89,22 @@ LLAvatarList::LLAvatarList(const Params& p)  	setComparator(&NAME_COMPARATOR);  } +void LLAvatarList::setShowIcons(std::string param_name) +{ +	mIconParamName= param_name; +	mShowIcons = gSavedSettings.getBOOL(mIconParamName); +} +  // virtual  void LLAvatarList::draw()  { -	if (mDirty) -		refresh(); +	// *NOTE dzaporozhan +	// Call refresh() after draw() to avoid flickering of avatar list items.  	LLFlatListView::draw(); + +	if (mDirty) +		refresh();  }  void LLAvatarList::setNameFilter(const std::string& filter) @@ -202,6 +227,7 @@ void LLAvatarList::addNewItem(const LLUUID& id, const std::string& name, BOOL is  	item->setContextMenu(mContextMenu);  	item->childSetVisible("info_btn", false); +	item->setAvatarIconVisible(mShowIcons);  	addItem(item, id, pos);  } diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index a83a72b26c..f60f1f00f3 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -70,7 +70,11 @@ public:  	void setContextMenu(LLAvatarListItem::ContextMenu* menu) { mContextMenu = menu; } +	void toggleIcons();  	void sortByName(); +	void setShowIcons(std::string param_name); +	bool getIconsVisible() const { return mShowIcons; } +	const std::string getIconParamName() const{return mIconParamName;}  	virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask);  protected: @@ -86,7 +90,9 @@ private:  	bool mIgnoreOnlineStatus;  	bool mDirty; +	bool mShowIcons; +	std::string				mIconParamName;  	std::string				mNameFilter;  	uuid_vector_t			mIDs; diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp index ebc79aae48..4ecb9537ba 100644 --- a/indra/newview/llavatarlistitem.cpp +++ b/indra/newview/llavatarlistitem.cpp @@ -42,6 +42,7 @@  #include "llavatariconctrl.h"  #include "llbutton.h" +S32 LLAvatarListItem::sIconWidth = 0;  LLAvatarListItem::LLAvatarListItem()  :	LLPanel(), @@ -55,6 +56,12 @@ LLAvatarListItem::LLAvatarListItem()  	mOnlineStatus(E_UNKNOWN)  {  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml"); +	// Remember avatar icon width including its padding from the name text box, +	// so that we can hide and show the icon again later. +	if (!sIconWidth) +	{ +		sIconWidth = mAvatarName->getRect().mLeft - mAvatarIcon->getRect().mLeft; +	}  }  LLAvatarListItem::~LLAvatarListItem() @@ -188,6 +195,21 @@ void LLAvatarListItem::setAvatarId(const LLUUID& id, bool ignore_status_changes)  	gCacheName->get(id, FALSE, boost::bind(&LLAvatarListItem::onNameCache, this, _2, _3));  } +void LLAvatarListItem::setAvatarIconVisible(bool visible) +{ +	// Already done? Then do nothing. +	if (mAvatarIcon->getVisible() == (BOOL)visible) +		return; + +	// Show/hide avatar icon. +	mAvatarIcon->setVisible(visible); + +	// Move the avatar name horizontally by icon size + its distance from the avatar name. +	LLRect name_rect = mAvatarName->getRect(); +	name_rect.mLeft += visible ? sIconWidth : -sIconWidth; +	mAvatarName->setRect(name_rect); +} +  void LLAvatarListItem::onInfoBtnClick()  {  	LLFloaterReg::showInstance("inspect_avatar", LLSD().insert("avatar_id", mAvatarId)); diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h index b9cfed4b7b..a8d3919217 100644 --- a/indra/newview/llavatarlistitem.h +++ b/indra/newview/llavatarlistitem.h @@ -64,6 +64,7 @@ public:  	void setOnline(bool online);  	void setName(const std::string& name);  	void setAvatarId(const LLUUID& id, bool ignore_status_changes = false); +	void setAvatarIconVisible(bool visible);  	const LLUUID& getAvatarId() const;  	const std::string getAvatarName() const; @@ -87,7 +88,7 @@ private:  	void onNameCache(const std::string& first_name, const std::string& last_name); -	LLAvatarIconCtrl*mAvatarIcon; +	LLAvatarIconCtrl* mAvatarIcon;  	LLTextBox* mAvatarName;  	LLTextBox* mStatus; @@ -98,6 +99,7 @@ private:  	LLUUID mAvatarId;  	EOnlineStatus mOnlineStatus; +	static S32	sIconWidth; // icon width + padding  };  #endif //LL_LLAVATARLISTITEM_H diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 77f941eef0..6427422572 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -40,6 +40,8 @@  #include "llbottomtray.h"  #include "llviewerwindow.h"  #include "llrootview.h" +#include "llsyswellwindow.h" +#include "llfloaterreg.h"  #include <algorithm> @@ -128,7 +130,7 @@ void LLChannelManager::onLoginCompleted()  	S32 channel_right_bound = gViewerWindow->getWorldViewRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin");   	S32 channel_width = gSavedSettings.getS32("NotifyBoxWidth");  	mStartUpChannel->init(channel_right_bound - channel_width, channel_right_bound); -	mStartUpChannel->setShowToasts(true); +	mStartUpChannel->setMouseDownCallback(boost::bind(&LLSysWellWindow::onStartUpToastClick, LLFloaterReg::getTypedInstance<LLSysWellWindow>("syswell_window"), _2, _3, _4));  	mStartUpChannel->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this));  	mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("StartUpToastLifeTime")); diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 94058365be..aaca568320 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -38,9 +38,215 @@  #include "llscrollcontainer.h"  #include "llavatariconctrl.h" +#include "llimview.h" +#include "llcallingcard.h" //for LLAvatarTracker +#include "llagentdata.h" +#include "llavataractions.h" +#include "lltrans.h" +  static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");  static const std::string MESSAGE_USERNAME_DATE_SEPARATOR(" ----- "); +std::string formatCurrentTime() +{ +	time_t utc_time; +	utc_time = time_corrected(); +	std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" +		+LLTrans::getString("TimeMin")+"] "; + +	LLSD substitution; + +	substitution["datetime"] = (S32) utc_time; +	LLStringUtil::format (timeStr, substitution); + +	return timeStr; +} + +class LLChatHistoryHeader: public LLPanel +{ +public: +	static LLChatHistoryHeader* createInstance(const std::string& file_name) +	{ +		LLChatHistoryHeader* pInstance = new LLChatHistoryHeader; +		LLUICtrlFactory::getInstance()->buildPanel(pInstance, file_name);	 +		return pInstance; +	} + +	BOOL handleMouseUp(S32 x, S32 y, MASK mask) +	{ +		return LLPanel::handleMouseUp(x,y,mask); +	} + +	void onAvatarIconContextMenuItemClicked(const LLSD& userdata) +	{ +		std::string level = userdata.asString(); + +		if (level == "profile") +		{ +			LLAvatarActions::showProfile(getAvatarId()); +		} +		else if (level == "im") +		{ +			LLAvatarActions::startIM(getAvatarId()); +		} +		else if (level == "add") +		{ +			std::string name; +			name.assign(getFirstName()); +			name.append(" "); +			name.append(getLastName()); + +			LLAvatarActions::requestFriendshipDialog(getAvatarId(), name); +		} +		else if (level == "remove") +		{ +			LLAvatarActions::removeFriendDialog(getAvatarId()); +		} +	} + +	BOOL postBuild() +	{ +		LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + +		registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2)); + +		LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + +		mPopupMenuHandleAvatar = menu->getHandle(); + +		return LLPanel::postBuild(); +	} + +	bool pointInChild(const std::string& name,S32 x,S32 y) +	{ +		LLUICtrl* child = findChild<LLUICtrl>(name); +		if(!child) +			return false; +		 +		LLView* parent = child->getParent(); +		if(parent!=this) +		{ +			x-=parent->getRect().mLeft; +			y-=parent->getRect().mBottom; +		} + +		S32 local_x = x - child->getRect().mLeft ; +		S32 local_y = y - child->getRect().mBottom ; +		return 	child->pointInView(local_x, local_y); +	} + +	BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) +	{ +		if(pointInChild("avatar_icon",x,y) || pointInChild("user_name",x,y)) +		{ +			showContextMenu(x,y); +			return TRUE; +		} + +		return LLPanel::handleRightMouseDown(x,y,mask); +	} +	const LLUUID&		getAvatarId () const { return mAvatarID;} +	const std::string&	getFirstName() const { return mFirstName; } +	const std::string&	getLastName	() const { return mLastName; } + +	void setup(const LLChat& chat)  +	{ +		mAvatarID = chat.mFromID; +		mSourceType = chat.mSourceType; +		gCacheName->get(mAvatarID, FALSE, boost::bind(&LLChatHistoryHeader::nameUpdatedCallback, this, _1, _2, _3, _4)); +		if(chat.mFromID.isNull()) +		{ +			mSourceType = CHAT_SOURCE_SYSTEM; +		} + + +		LLTextBox* userName = getChild<LLTextBox>("user_name"); +		 +		if(!chat.mFromName.empty()) +			userName->setValue(chat.mFromName); +		else +		{ +			std::string SL = LLTrans::getString("SECOND_LIFE"); +			userName->setValue(SL); +		} +		 +		LLTextBox* timeBox = getChild<LLTextBox>("time_box"); +		timeBox->setValue(formatCurrentTime()); + +		LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon"); + +		if(mSourceType != CHAT_SOURCE_AGENT) +			icon->setDrawTooltip(false); + +		if(!chat.mFromID.isNull()) +		{ +			icon->setValue(chat.mFromID); +		} + +	}  + +	void nameUpdatedCallback(const LLUUID& id,const std::string& first,const std::string& last,BOOL is_group) +	{ +		if (id != mAvatarID) +			return; +		mFirstName = first; +		mLastName = last; +	} +protected: +	void showContextMenu(S32 x,S32 y) +	{ +		if(mSourceType == CHAT_SOURCE_SYSTEM) +			showSystemContextMenu(x,y); +		if(mSourceType == CHAT_SOURCE_AGENT) +			showAvatarContextMenu(x,y); +		if(mSourceType == CHAT_SOURCE_OBJECT) +			showObjectContextMenu(x,y); +	} + +	void showSystemContextMenu(S32 x,S32 y) +	{ +	} +	void showObjectContextMenu(S32 x,S32 y) +	{ +	} +	 +	void showAvatarContextMenu(S32 x,S32 y) +	{ +		LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandleAvatar.get(); + +		if(menu) +		{ +			bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; +			 +			menu->setItemEnabled("Add Friend", !is_friend); +			menu->setItemEnabled("Remove Friend", is_friend); + +			if(gAgentID == mAvatarID) +			{ +				menu->setItemEnabled("Add Friend", false); +				menu->setItemEnabled("Send IM", false); +				menu->setItemEnabled("Remove Friend", false); +			} + +			menu->buildDrawLabels(); +			menu->updateParent(LLMenuGL::sMenuContainer); +			LLMenuGL::showPopup(this, menu, x, y); +		} +	} + +	 + +protected: +	LLHandle<LLView>	mPopupMenuHandleAvatar; + +	LLUUID			    mAvatarID; +	EChatSourceType		mSourceType; +	std::string			mFirstName; +	std::string			mLastName; + +}; + +  LLChatHistory::LLChatHistory(const LLChatHistory::Params& p)  : LLTextEditor(p),  mMessageHeaderFilename(p.message_header), @@ -48,7 +254,7 @@ mMessageSeparatorFilename(p.message_separator),  mLeftTextPad(p.left_text_pad),  mRightTextPad(p.right_text_pad),  mLeftWidgetPad(p.left_widget_pad), -mRightWidgetPad(p.rigth_widget_pad) +mRightWidgetPad(p.right_widget_pad)  {  } @@ -78,50 +284,49 @@ LLView* LLChatHistory::getSeparator()  	return separator;  } -LLView* LLChatHistory::getHeader(const LLUUID& avatar_id, std::string& from, std::string& time) +LLView* LLChatHistory::getHeader(const LLChat& chat)  { -	LLPanel* header = LLUICtrlFactory::getInstance()->createFromFile<LLPanel>(mMessageHeaderFilename, NULL, LLPanel::child_registry_t::instance()); -	LLTextBox* userName = header->getChild<LLTextBox>("user_name"); -	userName->setValue(from); -	LLTextBox* timeBox = header->getChild<LLTextBox>("time_box"); -	timeBox->setValue(time); -	if(!avatar_id.isNull()) -	{ -		LLAvatarIconCtrl* icon = header->getChild<LLAvatarIconCtrl>("avatar_icon"); -		icon->setValue(avatar_id); -	} +	LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename); +	header->setup(chat);  	return header;  } -void LLChatHistory::appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params) +void LLChatHistory::appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params)  {  	LLView* view = NULL;  	std::string view_text; -	if (mLastFromName == from) +	if (mLastFromName == chat.mFromName)  	{  		view = getSeparator();  		view_text = "\n";  	}  	else  	{ -		view = getHeader(avatar_id, from, time); -		view_text = from + MESSAGE_USERNAME_DATE_SEPARATOR + time + '\n'; +		view = getHeader(chat); +		view_text = chat.mFromName + MESSAGE_USERNAME_DATE_SEPARATOR + formatCurrentTime() + '\n';  	}  	//Prepare the rect for the view  	LLRect target_rect = getDocumentView()->getRect(); -	target_rect.mLeft += mLeftWidgetPad; +	// squeeze down the widget by subtracting padding off left and right +	target_rect.mLeft += mLeftWidgetPad + mHPad;  	target_rect.mRight -= mRightWidgetPad;  	view->reshape(target_rect.getWidth(), view->getRect().getHeight());  	view->setOrigin(target_rect.mLeft, view->getRect().mBottom); -	appendWidget(view, view_text, FALSE, TRUE, mLeftWidgetPad, 0); +	LLInlineViewSegment::Params p; +	p.view = view; +	p.force_newline = true; +	p.left_pad = mLeftWidgetPad; +	p.right_pad = mRightWidgetPad; + +	appendWidget(p, view_text, false);  	//Append the text message -	message += '\n'; +	std::string message = chat.mText + '\n';  	appendText(message, FALSE, style_params); -	mLastFromName = from; +	mLastFromName = chat.mFromName;  	blockUndo();  	setCursorAndScrollToEnd();  } diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h index d6eccf896a..92dcfdd958 100644 --- a/indra/newview/llchathistory.h +++ b/indra/newview/llchathistory.h @@ -34,6 +34,7 @@  #define LLCHATHISTORY_H_  #include "lltexteditor.h" +#include "llchat.h"  //Chat log widget allowing addition of a message as a widget   class LLChatHistory : public LLTextEditor @@ -52,7 +53,7 @@ class LLChatHistory : public LLTextEditor  			//Widget left padding from the scroll rect  			Optional<S32>			left_widget_pad;  			//Widget right padding from the scroll rect -			Optional<S32>			rigth_widget_pad; +			Optional<S32>			right_widget_pad;  			Params()  			:	message_header("message_header"), @@ -60,7 +61,7 @@ class LLChatHistory : public LLTextEditor  				left_text_pad("left_text_pad"),  				right_text_pad("right_text_pad"),  				left_widget_pad("left_widget_pad"), -				rigth_widget_pad("rigth_widget_pad") +				right_widget_pad("right_widget_pad")  				{  				} @@ -85,7 +86,7 @@ class LLChatHistory : public LLTextEditor  		 * @param time time of a message.  		 * @return pointer to LLView header object.  		 */ -		LLView* getHeader(const LLUUID& avatar_id, std::string& from, std::string& time); +		LLView* getHeader(const LLChat& chat);  	public:  		~LLChatHistory(); @@ -94,11 +95,11 @@ class LLChatHistory : public LLTextEditor  		 * Appends a widget message.  		 * If last user appended message, concurs with current user,  		 * separator is added before the message, otherwise header is added. -		 * @param from owner of a message. +		 * @param chat - base chat message.  		 * @param time time of a message.  		 * @param message message itself.  		 */ -		void appendWidgetMessage(const LLUUID& avatar_id, std::string& from, std::string& time, std::string& message, LLStyle::Params& style_params); +		void appendWidgetMessage(const LLChat& chat, LLStyle::Params& style_params);  	private:  		std::string mLastFromName; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 3b5b7f570e..a6afbc05be 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -503,13 +503,15 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con  		return;  	} +	LLPointer<LLViewerInventoryItem> viewer_item = new LLViewerInventoryItem(item); +  	if (dest)  	{ -		insertBeforeItem(mItems, dest->getLandmarkId(), item->getUUID()); +		insertBeforeItem(mItems, dest->getLandmarkId(), viewer_item);  	}  	else  	{ -		mItems.push_back(gInventory.getItem(item->getUUID())); +		mItems.push_back(viewer_item);  	}  	int sortField = 0; @@ -534,13 +536,22 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con  		}  	} -	copy_inventory_item( -			gAgent.getID(), -			item->getPermissions().getOwner(), -			item->getUUID(), -			favorites_id, -			std::string(), -			cb); +	LLToolDragAndDrop* tool_dad = LLToolDragAndDrop::getInstance(); +	if (tool_dad->getSource() == LLToolDragAndDrop::SOURCE_NOTECARD) +	{ +		viewer_item->setType(LLAssetType::AT_FAVORITE); +		copy_inventory_from_notecard(tool_dad->getObjectID(), tool_dad->getSourceID(), viewer_item.get(), gInventoryCallbacks.registerCB(cb)); +	} +	else +	{ +		copy_inventory_item( +				gAgent.getID(), +				item->getPermissions().getOwner(), +				item->getUUID(), +				favorites_id, +				std::string(), +				cb); +	}  	llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl;  } @@ -1263,10 +1274,9 @@ void LLFavoritesBarCtrl::updateItemsOrder(LLInventoryModel::item_array_t& items,  	items.insert(findItemByUUID(items, destItem->getUUID()), srcItem);  } -void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId) +void LLFavoritesBarCtrl::insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem)  {  	LLViewerInventoryItem* beforeItem = gInventory.getItem(beforeItemId); -	LLViewerInventoryItem* insertedItem = gInventory.getItem(insertedItemId);  	items.insert(findItemByUUID(items, beforeItem->getUUID()), insertedItem);  } diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index ea2a3d08e2..e90d13f9d5 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -141,7 +141,7 @@ private:  	 * inserts an item identified by insertedItemId BEFORE an item identified by beforeItemId.  	 * this function assumes that an item identified by insertedItemId doesn't exist in items array.  	 */ -	void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, const LLUUID& insertedItemId); +	void insertBeforeItem(LLInventoryModel::item_array_t& items, const LLUUID& beforeItemId, LLViewerInventoryItem* insertedItem);  	// finds an item by it's UUID in the items array  	LLInventoryModel::item_array_t::iterator findItemByUUID(LLInventoryModel::item_array_t& items, const LLUUID& id); diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index dea656b0e4..fbf09207fe 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -42,7 +42,7 @@  #include "llfloaterfriends.h"  #include "llfloatergroups.h"  #include "llviewercontrol.h" -#include "llimview.h" +#include "llvoicechannel.h"  #include "llimpanel.h"  // diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index c890f9f122..a47916b7d7 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1438,7 +1438,11 @@ void LLInventoryPanel::modelChanged(U32 mask)  						}  						LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); -						if (view_item->getParentFolder() != new_parent) + +						// added check against NULL for cases when Inventory panel contains startFolder. +						// in this case parent is LLFolderView (LLInventoryPanel::mFolders) itself. +						// this check is a fix for bug EXT-1859. +						if (NULL != new_parent && view_item->getParentFolder() != new_parent)  						{  							view_item->getParentFolder()->extractItem(view_item);  							view_item->addToFolder(new_parent, mFolders); diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index b64257b11d..aca9198f59 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -43,7 +43,7 @@  #include "llsliderctrl.h"  #include "llviewercontrol.h"  #include "llvoiceclient.h" -#include "llimpanel.h" +#include "llvoicechannel.h"  // Library includes (after viewer)  #include "lluictrlfactory.h" diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index a20b5ea66c..b86795f696 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -42,7 +42,6 @@  #include "llchiclet.h"  #include "llfloaterchat.h"  #include "llfloaterreg.h" -#include "llimview.h"  #include "lllineeditor.h"  #include "lllogchat.h"  #include "llpanelimcontrolpanel.h" @@ -50,6 +49,7 @@  #include "lltrans.h"  #include "llchathistory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lltransientfloatermgr.h" @@ -61,7 +61,14 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)  	mLastMessageIndex(-1),  	mDialog(IM_NOTHING_SPECIAL),  	mChatHistory(NULL), -	mInputEditor(NULL),  +	mInputEditor(NULL), +	mSavedTitle(), +	mTypingStart(), +	mShouldSendTypingState(false), +	mMeTyping(false), +	mOtherTyping(false), +	mTypingTimer(), +	mTypingTimeoutTimer(),  	mPositioned(false),  	mSessionInitialized(false)  { @@ -71,12 +78,15 @@ LLIMFloater::LLIMFloater(const LLUUID& session_id)  		mSessionInitialized = im_session->mSessionInitialized;  		mDialog = im_session->mType; -		if (IM_NOTHING_SPECIAL == mDialog || IM_SESSION_P2P_INVITE == mDialog) -		{ +		switch(mDialog){ +		case IM_NOTHING_SPECIAL: +		case IM_SESSION_P2P_INVITE:  			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); -		} -		else -		{ +			break; +		case IM_SESSION_CONFERENCE_START: +			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelAdHocControl, this); +			break; +		default:  			mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this);  		}  	} @@ -95,6 +105,7 @@ void LLIMFloater::onFocusReceived()  // virtual  void LLIMFloater::onClose(bool app_quitting)  { +	setTyping(false);  	gIMMgr->leaveSession(mSessionID);  } @@ -141,6 +152,7 @@ void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata )  {  	LLIMFloater* self = (LLIMFloater*) userdata;  	self->sendMsg(); +	self->setTyping(false);  }  void LLIMFloater::sendMsg() @@ -193,9 +205,10 @@ BOOL LLIMFloater::postBuild()  	if (other_party_id.notNull())  	{  		mOtherParticipantUUID = other_party_id; -		mControlPanel->setID(mOtherParticipantUUID);  	} +	mControlPanel->setSessionId(mSessionID); +  	LLButton* slide_left = getChild<LLButton>("slide_left_btn");  	slide_left->setVisible(mControlPanel->getVisible());  	slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this)); @@ -228,12 +241,37 @@ BOOL LLIMFloater::postBuild()  		LLLogChat::loadHistory(getTitle(), &chatFromLogFile, (void *)this);  	} +	mTypingStart = LLTrans::getString("IM_typing_start_string"); + +	// Disable input editor if session cannot accept text +	LLIMModel::LLIMSession* im_session = +		LLIMModel::instance().findIMSession(mSessionID); +	if( im_session && !im_session->mTextIMPossible ) +	{ +		mInputEditor->setEnabled(FALSE); +		mInputEditor->setLabel(LLTrans::getString("IM_unavailable_text_label")); +	} +  	//*TODO if session is not initialized yet, add some sort of a warning message like "starting session...blablabla"  	//see LLFloaterIMPanel for how it is done (IB)  	return LLDockableFloater::postBuild();  } +// virtual +void LLIMFloater::draw() +{ +	if ( mMeTyping ) +	{ +		// Time out if user hasn't typed for a while. +		if ( mTypingTimeoutTimer.getElapsedTimeF32() > LLAgent::TYPING_TIMEOUT_SECS ) +		{ +			setTyping(false); +		} +	} + +	LLFloater::draw(); +}  // static @@ -255,6 +293,15 @@ void* LLIMFloater::createPanelGroupControl(void* userdata)  	return self->mControlPanel;  } +// static +void* LLIMFloater::createPanelAdHocControl(void* userdata) +{ +	LLIMFloater *self = (LLIMFloater*)userdata; +	self->mControlPanel = new LLPanelAdHocControlPanel(self->mSessionID); +	self->mControlPanel->setXMLFilename("panel_adhoc_control_panel.xml"); +	return self->mControlPanel; +} +  void LLIMFloater::onSlide()  {  	LLPanel* im_control_panel = getChild<LLPanel>("panel_im_control_panel"); @@ -379,10 +426,12 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)  {  	mSessionInitialized = true; +	//will be different only for an ad-hoc im session  	if (mSessionID != im_session_id)  	{  		mSessionID = im_session_id;  		setKey(im_session_id); +		mControlPanel->setSessionId(im_session_id);  	}  	//*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB) @@ -402,7 +451,8 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id)  void LLIMFloater::updateMessages()  { -	std::list<LLSD> messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1); +	std::list<LLSD> messages; +	LLIMModel::instance().getMessages(mSessionID, messages, mLastMessageIndex+1);  	std::string agent_name;  	gCacheName->getFullName(gAgentID, agent_name); @@ -428,7 +478,11 @@ void LLIMFloater::updateMessages()  			if (from == agent_name)  				from = LLTrans::getString("You"); -			mChatHistory->appendWidgetMessage(from_id, from, time, message, style_params); +			LLChat chat(message); +			chat.mFromID = from_id; +			chat.mFromName = from; + +			mChatHistory->appendWidgetMessage(chat, style_params);  			mLastMessageIndex = msg["index"].asInteger();  		} @@ -440,9 +494,14 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*  {  	LLIMFloater* self= (LLIMFloater*) userdata; -	//in disconnected state IM input editor should be disabled -	self->mInputEditor->setEnabled(!gDisconnected); - +	// Allow enabling the LLIMFloater input editor only if session can accept text +	LLIMModel::LLIMSession* im_session = +		LLIMModel::instance().findIMSession(self->mSessionID); +	if( im_session && im_session->mTextIMPossible ) +	{ +		//in disconnected state IM input editor should be disabled +		self->mInputEditor->setEnabled(!gDisconnected); +	}  	self->mChatHistory->setCursorAndScrollToEnd();  } @@ -450,7 +509,7 @@ void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void*  void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata)  {  	LLIMFloater* self = (LLIMFloater*) userdata; -	self->setTyping(FALSE); +	self->setTyping(false);  }  // static @@ -460,19 +519,142 @@ void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata)  	std::string text = self->mInputEditor->getText();  	if (!text.empty())  	{ -		self->setTyping(TRUE); +		self->setTyping(true);  	}  	else  	{  		// Deleting all text counts as stopping typing. -		self->setTyping(FALSE); +		self->setTyping(false);  	}  } +void LLIMFloater::setTyping(bool typing) +{ +	if ( typing ) +	{ +		// Started or proceeded typing, reset the typing timeout timer +		mTypingTimeoutTimer.reset(); +	} + +	if ( mMeTyping != typing ) +	{ +		// Typing state is changed +		mMeTyping = typing; +		// So, should send current state +		mShouldSendTypingState = true; +		// In case typing is started, send state after some delay +		mTypingTimer.reset(); +	} + +	// Don't want to send typing indicators to multiple people, potentially too +	// much network traffic. Only send in person-to-person IMs. +	if ( mShouldSendTypingState && mDialog == IM_NOTHING_SPECIAL ) +	{ +		if ( mMeTyping ) +		{ +			if ( mTypingTimer.getElapsedTimeF32() > 1.f ) +			{ +				// Still typing, send 'start typing' notification +				LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, TRUE); +				mShouldSendTypingState = false; +			} +		} +		else +		{ +			// Send 'stop typing' notification immediately +			LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, FALSE); +			mShouldSendTypingState = false; +		} +	} -//just a stub for now -void LLIMFloater::setTyping(BOOL typing) +	LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +	if (speaker_mgr) +		speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); + +} + +void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing) +{ +	if ( typing ) +	{ +		// other user started typing +		addTypingIndicator(im_info); +	} +	else +	{ +		// other user stopped typing +		removeTypingIndicator(im_info); +	} +} + +void LLIMFloater::processSessionUpdate(const LLSD& session_update) +{ +	// *TODO : verify following code when moderated mode will be implemented +	if ( false && session_update.has("moderated_mode") && +		 session_update["moderated_mode"].has("voice") ) +	{ +		BOOL voice_moderated = session_update["moderated_mode"]["voice"]; +		const std::string session_label = LLIMModel::instance().getName(mSessionID); + +		if (voice_moderated) +		{ +			setTitle(session_label + std::string(" ") + LLTrans::getString("IM_moderated_chat_label")); +		} +		else +		{ +			setTitle(session_label); +		} + +		// *TODO : uncomment this when/if LLPanelActiveSpeakers panel will be added +		//update the speakers dropdown too +		//mSpeakerPanel->setVoiceModerationCtrlMode(voice_moderated); +	} +} + +void LLIMFloater::addTypingIndicator(const LLIMInfo* im_info)  { +	// We may have lost a "stop-typing" packet, don't add it twice +	if ( im_info && !mOtherTyping ) +	{ +		mOtherTyping = true; + +		// Create typing is started title string +		LLUIString typing_start(mTypingStart); +		typing_start.setArg("[NAME]", im_info->mName); + +		// Save and set new title +		mSavedTitle = getTitle(); +		setTitle (typing_start); + +		// Update speaker +		LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +		if ( speaker_mgr ) +		{ +			speaker_mgr->setSpeakerTyping(im_info->mFromID, TRUE); +		} +	} +} + +void LLIMFloater::removeTypingIndicator(const LLIMInfo* im_info) +{ +	if ( mOtherTyping ) +	{ +		mOtherTyping = false; + +		// Revert the title to saved one +		setTitle(mSavedTitle); + +		if ( im_info ) +		{ +			// Update speaker +			LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); +			if ( speaker_mgr ) +			{ +				speaker_mgr->setSpeakerTyping(im_info->mFromID, FALSE); +			} +		} + +	}  }  void LLIMFloater::chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata) diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 99810b6d6d..3da27ac941 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -55,6 +55,8 @@ public:  	// LLView overrides  	/*virtual*/ BOOL postBuild();  	/*virtual*/ void setVisible(BOOL visible); +	// Check typing timeout timer. +	/*virtual*/ void draw();  	// LLFloater overrides  	/*virtual*/ void onClose(bool app_quitting); @@ -85,6 +87,8 @@ public:  	void setPositioned(bool b) { mPositioned = b; };  	void onVisibilityChange(const LLSD& new_visibility); +	void processIMTyping(const LLIMInfo* im_info, BOOL typing); +	void processSessionUpdate(const LLSD& session_update);  private:  	// process focus events to set a currently active session @@ -94,15 +98,21 @@ private:  	static void		onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata );  	static void		onInputEditorFocusLost(LLFocusableElement* caller, void* userdata);  	static void		onInputEditorKeystroke(LLLineEditor* caller, void* userdata); -	void			setTyping(BOOL typing); +	void			setTyping(bool typing);  	void			onSlide();  	static void*	createPanelIMControl(void* userdata);  	static void*	createPanelGroupControl(void* userdata); +	static void* 	createPanelAdHocControl(void* userdata);  	// gets a rect that bounds possible positions for the LLIMFloater on a screen (EXT-1111)  	void getAllowedRect(LLRect& rect);  	static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); +	// Add the "User is typing..." indicator. +	void addTypingIndicator(const LLIMInfo* im_info); + +	// Remove the "User is typing..." indicator. +	void removeTypingIndicator(const LLIMInfo* im_info = NULL);  	LLPanelChatControlPanel* mControlPanel;  	LLUUID mSessionID; @@ -114,6 +124,14 @@ private:  	LLLineEditor* mInputEditor;  	bool mPositioned; +	std::string mSavedTitle; +	LLUIString mTypingStart; +	bool mMeTyping; +	bool mOtherTyping; +	bool mShouldSendTypingState; +	LLFrameTimer mTypingTimer; +	LLFrameTimer mTypingTimeoutTimer; +  	bool mSessionInitialized;  	LLSD mQueuedMsgsForInit;  }; diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 163984f740..77ee90f681 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -54,6 +54,7 @@  #include "llconsole.h"  #include "llgroupactions.h"  #include "llfloater.h" +#include "llfloateractivespeakers.h"  #include "llfloatercall.h"  #include "llavataractions.h"  #include "llimview.h" @@ -77,6 +78,7 @@  #include "llviewercontrol.h"  #include "lluictrlfactory.h"  #include "llviewerwindow.h" +#include "llvoicechannel.h"  #include "lllogchat.h"  #include "llweb.h"  #include "llhttpclient.h" @@ -90,7 +92,6 @@  const S32 LINE_HEIGHT = 16;  const S32 MIN_WIDTH = 200;  const S32 MIN_HEIGHT = 130; -const U32 DEFAULT_RETRIES_COUNT = 3;  //  // Statics @@ -100,831 +101,6 @@ static std::string sTitleString = "Instant Message with [NAME]";  static std::string sTypingStartString = "[NAME]: ...";  static std::string sSessionStartString = "Starting session with [NAME] please wait."; -LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; -LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; -LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; -LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; - -BOOL LLVoiceChannel::sSuspended = FALSE; - - - -class LLVoiceCallCapResponder : public LLHTTPClient::Responder -{ -public: -	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; - -	virtual void error(U32 status, const std::string& reason);	// called with bad status codes -	virtual void result(const LLSD& content); - -private: -	LLUUID mSessionID; -}; - - -void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) -{ -	llwarns << "LLVoiceCallCapResponder::error(" -		<< status << ": " << reason << ")" -		<< llendl; -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if ( channelp ) -	{ -		if ( 403 == status ) -		{ -			//403 == no ability -			LLNotifications::instance().add( -				"VoiceNotAllowed", -				channelp->getNotifyArgs()); -		} -		else -		{ -			LLNotifications::instance().add( -				"VoiceCallGenericError", -				channelp->getNotifyArgs()); -		} -		channelp->deactivate(); -	} -} - -void LLVoiceCallCapResponder::result(const LLSD& content) -{ -	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); -	if (channelp) -	{ -		//*TODO: DEBUG SPAM -		LLSD::map_const_iterator iter; -		for(iter = content.beginMap(); iter != content.endMap(); ++iter) -		{ -			llinfos << "LLVoiceCallCapResponder::result got "  -				<< iter->first << llendl; -		} - -		channelp->setChannelInfo( -			content["voice_credentials"]["channel_uri"].asString(), -			content["voice_credentials"]["channel_credentials"].asString()); -	} -} - -// -// LLVoiceChannel -// -LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  -	mSessionID(session_id),  -	mState(STATE_NO_CHANNEL_INFO),  -	mSessionName(session_name), -	mIgnoreNextSessionLeave(FALSE) -{ -	mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; - -	if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) -	{ -		// a voice channel already exists for this session id, so this instance will be orphaned -		// the end result should simply be the failure to make voice calls -		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; -	} - -	LLVoiceClient::getInstance()->addObserver(this); -} - -LLVoiceChannel::~LLVoiceChannel() -{ -	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. -	if(gVoiceClient) -	{ -		gVoiceClient->removeObserver(this); -	} -	 -	sVoiceChannelMap.erase(mSessionID); -	sVoiceChannelURIMap.erase(mURI); -} - -void LLVoiceChannel::setChannelInfo( -	const std::string& uri, -	const std::string& credentials) -{ -	setURI(uri); - -	mCredentials = credentials; - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		if (mURI.empty()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty URI for channel " << mSessionName << llendl; -			deactivate(); -		} -		else if (mCredentials.empty()) -		{ -			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); -			llwarns << "Received empty credentials for channel " << mSessionName << llendl; -			deactivate(); -		} -		else -		{ -			setState(STATE_READY); - -			// if we are supposed to be active, reconnect -			// this will happen on initial connect, as we request credentials on first use -			if (sCurrentVoiceChannel == this) -			{ -				// just in case we got new channel info while active -				// should move over to new channel -				activate(); -			} -		} -	} -} - -void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal) -{ -	if (channelURI != mURI) -	{ -		return; -	} - -	if (type < BEGIN_ERROR_STATUS) -	{ -		handleStatusChange(type); -	} -	else -	{ -		handleError(type); -	} -} - -void LLVoiceChannel::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LOGIN_RETRY: -		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); -		LLNotifications::instance().add("VoiceLoginRetry"); -		break; -	case STATUS_LOGGED_IN: -		//if (!mLoginNotificationHandle.isDead()) -		//{ -		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); -		//	if (notifyp) -		//	{ -		//		notifyp->close(); -		//	} -		//	mLoginNotificationHandle.markDead(); -		//} -		break; -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			// if forceably removed from channel -			// update the UI and revert to default channel -			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		break; -	case STATUS_JOINING: -		if (callStarted()) -		{ -			setState(STATE_RINGING); -		} -		break; -	case STATUS_JOINED: -		if (callStarted()) -		{ -			setState(STATE_CONNECTED); -		} -	default: -		break; -	} -} - -// default behavior is to just deactivate channel -// derived classes provide specific error messages -void LLVoiceChannel::handleError(EStatusType type) -{ -	deactivate(); -	setState(STATE_ERROR); -} - -BOOL LLVoiceChannel::isActive() -{  -	// only considered active when currently bound channel matches what our channel -	return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  -} - -BOOL LLVoiceChannel::callStarted() -{ -	return mState >= STATE_CALL_STARTED; -} - -void LLVoiceChannel::deactivate() -{ -	if (mState >= STATE_RINGING) -	{ -		// ignore session leave event -		mIgnoreNextSessionLeave = TRUE; -	} - -	if (callStarted()) -	{ -		setState(STATE_HUNG_UP); -		// mute the microphone if required when returning to the proximal channel -		if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) -		{ -			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); -		} -	} - -	if (sCurrentVoiceChannel == this) -	{ -		// default channel is proximal channel -		sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); -		sCurrentVoiceChannel->activate(); -	} -} - -void LLVoiceChannel::activate() -{ -	if (callStarted()) -	{ -		return; -	} - -	// deactivate old channel and mark ourselves as the active one -	if (sCurrentVoiceChannel != this) -	{ -		// mark as current before deactivating the old channel to prevent -		// activating the proximal channel between IM calls -		LLVoiceChannel* old_channel = sCurrentVoiceChannel; -		sCurrentVoiceChannel = this; -		if (old_channel) -		{ -			old_channel->deactivate(); -		} -	} - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		// responsible for setting status to active -		getChannelInfo(); -	} -	else -	{ -		setState(STATE_CALL_STARTED); -	} -} - -void LLVoiceChannel::getChannelInfo() -{ -	// pretend we have everything we need -	if (sCurrentVoiceChannel == this) -	{ -		setState(STATE_CALL_STARTED); -	} -} - -//static  -LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) -{ -	voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); -	if (found_it == sVoiceChannelMap.end()) -	{ -		return NULL; -	} -	else -	{ -		return found_it->second; -	} -} - -//static  -LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) -{ -	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); -	if (found_it == sVoiceChannelURIMap.end()) -	{ -		return NULL; -	} -	else -	{ -		return found_it->second; -	} -} - -void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) -{ -	sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); -	mSessionID = new_session_id; -	sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); -} - -void LLVoiceChannel::setURI(std::string uri) -{ -	sVoiceChannelURIMap.erase(mURI); -	mURI = uri; -	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); -} - -void LLVoiceChannel::setState(EState state) -{ -	switch(state) -	{ -	case STATE_RINGING: -		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		break; -	case STATE_CONNECTED: -		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); -		break; -	case STATE_HUNG_UP: -		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); -		break; -	default: -		break; -	} - -	mState = state; -} - -void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) -{ -	if (state == STATE_CONNECTED) -	{ -		LLFloaterReg::showInstance("voice_call", mSessionID); -	} -	// By checking that current state is CONNECTED we make sure that the call window -	// has been shown, hence there's something to hide. This helps when user presses -	// the "End call" button right after initiating the call. -	// *TODO: move this check to LLFloaterCall? -	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) -	{ -		LLFloaterReg::hideInstance("voice_call", mSessionID); -	} -} - -//static -void LLVoiceChannel::initClass() -{ -	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); -} - - -//static  -void LLVoiceChannel::suspend() -{ -	if (!sSuspended) -	{ -		sSuspendedVoiceChannel = sCurrentVoiceChannel; -		sSuspended = TRUE; -	} -} - -//static  -void LLVoiceChannel::resume() -{ -	if (sSuspended) -	{ -		if (gVoiceClient->voiceEnabled()) -		{ -			if (sSuspendedVoiceChannel) -			{ -				sSuspendedVoiceChannel->activate(); -			} -			else -			{ -				LLVoiceChannelProximal::getInstance()->activate(); -			} -		} -		sSuspended = FALSE; -	} -} - - -// -// LLVoiceChannelGroup -// - -LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  -	LLVoiceChannel(session_id, session_name) -{ -	mRetries = DEFAULT_RETRIES_COUNT; -	mIsRetrying = FALSE; -} - -void LLVoiceChannelGroup::deactivate() -{ -	if (callStarted()) -	{ -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -	LLVoiceChannel::deactivate(); -} - -void LLVoiceChannelGroup::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// we have the channel info, just need to use it now -		LLVoiceClient::getInstance()->setNonSpatialChannel( -			mURI, -			mCredentials); - -#if 0 // *TODO -		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel -		{ -			// Add the party to the list of people with which we've recently interacted. -			for (/*people in the chat*/) -				LLRecentPeople::instance().add(buddy_id); -		} -#endif -	} -} - -void LLVoiceChannelGroup::getChannelInfo() -{ -	LLViewerRegion* region = gAgent.getRegion(); -	if (region) -	{ -		std::string url = region->getCapability("ChatSessionRequest"); -		LLSD data; -		data["method"] = "call"; -		data["session-id"] = mSessionID; -		LLHTTPClient::post(url, -						   data, -						   new LLVoiceCallCapResponder(mSessionID)); -	} -} - -void LLVoiceChannelGroup::setChannelInfo( -	const std::string& uri, -	const std::string& credentials) -{ -	setURI(uri); - -	mCredentials = credentials; - -	if (mState == STATE_NO_CHANNEL_INFO) -	{ -		if(!mURI.empty() && !mCredentials.empty()) -		{ -			setState(STATE_READY); - -			// if we are supposed to be active, reconnect -			// this will happen on initial connect, as we request credentials on first use -			if (sCurrentVoiceChannel == this) -			{ -				// just in case we got new channel info while active -				// should move over to new channel -				activate(); -			} -		} -		else -		{ -			//*TODO: notify user -			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; -			deactivate(); -		} -	} -	else if ( mIsRetrying ) -	{ -		// we have the channel info, just need to use it now -		LLVoiceClient::getInstance()->setNonSpatialChannel( -			mURI, -			mCredentials); -	} -} - -void LLVoiceChannelGroup::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_JOINED: -		mRetries = 3; -		mIsRetrying = FALSE; -	default: -		break; -	} - -	LLVoiceChannel::handleStatusChange(type); -} - -void LLVoiceChannelGroup::handleError(EStatusType status) -{ -	std::string notify; -	switch(status) -	{ -	case ERROR_CHANNEL_LOCKED: -	case ERROR_CHANNEL_FULL: -		notify = "VoiceChannelFull"; -		break; -	case ERROR_NOT_AVAILABLE: -		//clear URI and credentials -		//set the state to be no info -		//and activate -		if ( mRetries > 0 ) -		{ -			mRetries--; -			mIsRetrying = TRUE; -			mIgnoreNextSessionLeave = TRUE; - -			getChannelInfo(); -			return; -		} -		else -		{ -			notify = "VoiceChannelJoinFailed"; -			mRetries = DEFAULT_RETRIES_COUNT; -			mIsRetrying = FALSE; -		} - -		break; - -	case ERROR_UNKNOWN: -	default: -		break; -	} - -	// notification -	if (!notify.empty()) -	{ -		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); -		// echo to im window -		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelGroup::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	switch(state) -	{ -	case STATE_RINGING: -		if ( !mIsRetrying ) -		{ -			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); -		} - -		mState = state; -		break; -	default: -		LLVoiceChannel::setState(state); -	} -} - -// -// LLVoiceChannelProximal -// -LLVoiceChannelProximal::LLVoiceChannelProximal() :  -	LLVoiceChannel(LLUUID::null, LLStringUtil::null) -{ -	activate(); -} - -BOOL LLVoiceChannelProximal::isActive() -{ -	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  -} - -void LLVoiceChannelProximal::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// this implicitly puts you back in the spatial channel -		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); -	} -} - -void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) -{ -	if (!proximal) -	{ -		return; -	} - -	if (type < BEGIN_ERROR_STATUS) -	{ -		handleStatusChange(type); -	} -	else -	{ -		handleError(type); -	} -} - -void LLVoiceChannelProximal::handleStatusChange(EStatusType status) -{ -	// status updates -	switch(status) -	{ -	case STATUS_LEFT_CHANNEL: -		// do not notify user when leaving proximal channel -		return; -	case STATUS_VOICE_DISABLED: -		 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs); -		return; -	default: -		break; -	} -	LLVoiceChannel::handleStatusChange(status); -} - - -void LLVoiceChannelProximal::handleError(EStatusType status) -{ -	std::string notify; -	switch(status) -	{ -	  case ERROR_CHANNEL_LOCKED: -	  case ERROR_CHANNEL_FULL: -		notify = "ProximalVoiceChannelFull"; -		break; -	  default: -		 break; -	} - -	// notification -	if (!notify.empty()) -	{ -		LLNotifications::instance().add(notify, mNotifyArgs); -	} - -	LLVoiceChannel::handleError(status); -} - -void LLVoiceChannelProximal::deactivate() -{ -	if (callStarted()) -	{ -		setState(STATE_HUNG_UP); -	} -} - - -// -// LLVoiceChannelP2P -// -LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :  -		LLVoiceChannelGroup(session_id, session_name),  -		mOtherUserID(other_user_id), -		mReceivedCall(FALSE) -{ -	// make sure URI reflects encoded version of other user's agent id -	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); -} - -void LLVoiceChannelP2P::handleStatusChange(EStatusType type) -{ -	// status updates -	switch(type) -	{ -	case STATUS_LEFT_CHANNEL: -		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) -		{ -			if (mState == STATE_RINGING) -			{ -				// other user declined call -				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); -			} -			else -			{ -				// other user hung up -				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); -			} -			deactivate(); -		} -		mIgnoreNextSessionLeave = FALSE; -		return; -	default: -		break; -	} - -	LLVoiceChannel::handleStatusChange(type); -} - -void LLVoiceChannelP2P::handleError(EStatusType type) -{ -	switch(type) -	{ -	case ERROR_NOT_AVAILABLE: -		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); -		break; -	default: -		break; -	} - -	LLVoiceChannel::handleError(type); -} - -void LLVoiceChannelP2P::activate() -{ -	if (callStarted()) return; - -	LLVoiceChannel::activate(); - -	if (callStarted()) -	{ -		// no session handle yet, we're starting the call -		if (mSessionHandle.empty()) -		{ -			mReceivedCall = FALSE; -			LLVoiceClient::getInstance()->callUser(mOtherUserID); -		} -		// otherwise answering the call -		else -		{ -			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); -			 -			// using the session handle invalidates it.  Clear it out here so we can't reuse it by accident. -			mSessionHandle.clear(); -		} - -		// Add the party to the list of people with which we've recently interacted. -		LLRecentPeople::instance().add(mOtherUserID); -	} -} - -void LLVoiceChannelP2P::getChannelInfo() -{ -	// pretend we have everything we need, since P2P doesn't use channel info -	if (sCurrentVoiceChannel == this) -	{ -		setState(STATE_CALL_STARTED); -	} -} - -// receiving session from other user who initiated call -void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI) -{  -	BOOL needs_activate = FALSE; -	if (callStarted()) -	{ -		// defer to lower agent id when already active -		if (mOtherUserID < gAgent.getID()) -		{ -			// pretend we haven't started the call yet, so we can connect to this session instead -			deactivate(); -			needs_activate = TRUE; -		} -		else -		{ -			// we are active and have priority, invite the other user again -			// under the assumption they will join this new session -			mSessionHandle.clear(); -			LLVoiceClient::getInstance()->callUser(mOtherUserID); -			return; -		} -	} - -	mSessionHandle = handle; - -	// The URI of a p2p session should always be the other end's SIP URI. -	if(!inURI.empty()) -	{ -		setURI(inURI); -	} -	else -	{ -		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); -	} -	 -	mReceivedCall = TRUE; - -	if (needs_activate) -	{ -		activate(); -	} -} - -void LLVoiceChannelP2P::setState(EState state) -{ -	// HACK: Open/close the call window if needed. -	toggleCallWindowIfNeeded(state); - -	// you only "answer" voice invites in p2p mode -	// so provide a special purpose message here -	if (mReceivedCall && state == STATE_RINGING) -	{ -		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); -		mState = state; -		return; -	} -	LLVoiceChannel::setState(state); -} -  //  // LLFloaterIMPanel @@ -1836,75 +1012,8 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string  	self->mHistoryEditor->blockUndo();  } -void LLFloaterIMPanel::showSessionStartError( -	const std::string& error_string) -{ -	LLSD args; -	args["REASON"] = LLTrans::getString(error_string); -	args["RECIPIENT"] = getTitle(); - -	LLSD payload; -	payload["session_id"] = mSessionUUID; - -	LLNotifications::instance().add( -		"ChatterBoxSessionStartError", -		args, -		payload, -		onConfirmForceCloseError); -} - -void LLFloaterIMPanel::showSessionEventError( -	const std::string& event_string, -	const std::string& error_string) -{ -	LLSD args; -	args["REASON"] = -		LLTrans::getString(error_string); -	args["EVENT"] = -		LLTrans::getString(event_string); -	args["RECIPIENT"] = getTitle(); - -	LLNotifications::instance().add( -		"ChatterBoxSessionEventError", -		args); -} - -void LLFloaterIMPanel::showSessionForceClose( -	const std::string& reason_string) -{ -	LLSD args; - -	args["NAME"] = getTitle(); -	args["REASON"] = LLTrans::getString(reason_string); - -	LLSD payload; -	payload["session_id"] = mSessionUUID; - -	LLNotifications::instance().add( -		"ForceCloseChatterBoxSession", -		args, -		payload, -		LLFloaterIMPanel::onConfirmForceCloseError); - -} -  //static   void LLFloaterIMPanel::onKickSpeaker(void* user_data)  {  } - -bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLSD& response) -{ -	//only 1 option really -	LLUUID session_id = notification["payload"]["session_id"]; - -	if ( gIMMgr ) -	{ -		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession( -			session_id); - -		if ( floaterp ) floaterp->closeFloater(FALSE); -	} -	return false; -} diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 4e306c7fab..39107d9a22 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -50,133 +50,6 @@ class LLIMSpeakerMgr;  class LLPanelActiveSpeakers;  class LLPanelChatControlPanel; -class LLVoiceChannel : public LLVoiceClientStatusObserver -{ -public: -	typedef enum e_voice_channel_state -	{ -		STATE_NO_CHANNEL_INFO, -		STATE_ERROR, -		STATE_HUNG_UP, -		STATE_READY, -		STATE_CALL_STARTED, -		STATE_RINGING, -		STATE_CONNECTED -	} EState; - -	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); -	virtual ~LLVoiceChannel(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); - -	virtual void handleStatusChange(EStatusType status); -	virtual void handleError(EStatusType status); -	virtual void deactivate(); -	virtual void activate(); -	virtual void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	virtual void getChannelInfo(); -	virtual BOOL isActive(); -	virtual BOOL callStarted(); -	const std::string& getSessionName() const { return mSessionName; } - -	const LLUUID getSessionID() { return mSessionID; } -	EState getState() { return mState; } - -	void updateSessionID(const LLUUID& new_session_id); -	const LLSD& getNotifyArgs() { return mNotifyArgs; } - -	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); -	static LLVoiceChannel* getChannelByURI(std::string uri); -	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } -	static void initClass(); -	 -	static void suspend(); -	static void resume(); - -protected: -	virtual void setState(EState state); -	void toggleCallWindowIfNeeded(EState state); -	void setURI(std::string uri); - -	std::string	mURI; -	std::string	mCredentials; -	LLUUID		mSessionID; -	EState		mState; -	std::string	mSessionName; -	LLSD mNotifyArgs; -	BOOL		mIgnoreNextSessionLeave; -	LLHandle<LLPanel> mLoginNotificationHandle; - -	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; -	static voice_channel_map_t sVoiceChannelMap; - -	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; -	static voice_channel_map_uri_t sVoiceChannelURIMap; - -	static LLVoiceChannel* sCurrentVoiceChannel; -	static LLVoiceChannel* sSuspendedVoiceChannel; -	static BOOL sSuspended; -}; - -class LLVoiceChannelGroup : public LLVoiceChannel -{ -public: -	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); -	/*vritual*/ void setChannelInfo( -		const std::string& uri, -		const std::string& credentials); -	/*virtual*/ void getChannelInfo(); - -protected: -	virtual void setState(EState state); - -private: -	U32 mRetries; -	BOOL mIsRetrying; -}; - -class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> -{ -public: -	LLVoiceChannelProximal(); - -	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -	/*virtual*/ BOOL isActive(); -	/*virtual*/ void activate(); -	/*virtual*/ void deactivate(); - -}; - -class LLVoiceChannelP2P : public LLVoiceChannelGroup -{ -public: -	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); - -	/*virtual*/ void handleStatusChange(EStatusType status); -	/*virtual*/ void handleError(EStatusType status); -    /*virtual*/ void activate(); -	/*virtual*/ void getChannelInfo(); - -	void setSessionHandle(const std::string& handle, const std::string &inURI); - -protected: -	virtual void setState(EState state); - -private: -	std::string	mSessionHandle; -	LLUUID		mOtherUserID; -	BOOL		mReceivedCall; -}; -  class LLFloaterIMPanel : public LLFloater  {  public: @@ -256,15 +129,6 @@ public:  	void processIMTyping(const LLIMInfo* im_info, BOOL typing);  	static void chatFromLogFile(LLLogChat::ELogLineType type, std::string line, void* userdata); -	//show error statuses to the user -	void showSessionStartError(const std::string& error_string); -	void showSessionEventError( -		const std::string& event_string, -		const std::string& error_string); -	void showSessionForceClose(const std::string& reason); - -	static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); -  private:  	// Called by UI methods.  	void sendMsg(); diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index b631c991ae..8a55ab41b9 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -70,6 +70,7 @@  #include "llviewerwindow.h"  #include "llnotify.h"  #include "llviewerregion.h" +#include "llvoicechannel.h"  #include "lltrans.h"  #include "llrecentpeople.h" @@ -144,7 +145,10 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&  	mInitialTargetIDs(ids),  	mVoiceChannel(NULL),  	mSpeakers(NULL), -	mSessionInitialized(false) +	mSessionInitialized(false), +	mCallBackEnabled(true), +	mTextIMPossible(true), +	mOtherParticipantIsAvatar(true)  {  	if (IM_NOTHING_SPECIAL == type || IM_SESSION_P2P_INVITE == type)  	{ @@ -168,6 +172,13 @@ LLIMModel::LLIMSession::LLIMSession(const LLUUID& session_id, const std::string&  		//so we're already initialized  		mSessionInitialized = true;  	} + +	if (IM_NOTHING_SPECIAL == type) +	{ +		mCallBackEnabled = LLVoiceClient::getInstance()->isSessionCallBackPossible(mSessionID); +		mTextIMPossible = LLVoiceClient::getInstance()->isSessionTextIMPossible(mSessionID); +		mOtherParticipantIsAvatar = LLVoiceClient::getInstance()->isParticipantAvatar(mSessionID); +	}  }  LLIMModel::LLIMSession::~LLIMSession() @@ -272,7 +283,8 @@ void LLIMModel::testMessages()  } -bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id, const std::vector<LLUUID>& ids) +bool LLIMModel::newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type,  +						   const LLUUID& other_participant_id, const std::vector<LLUUID>& ids)  {  	if (is_in_map(sSessionsMap, session_id))  	{ @@ -289,7 +301,7 @@ bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage  } -bool LLIMModel::clearSession(LLUUID session_id) +bool LLIMModel::clearSession(const LLUUID& session_id)  {  	if (sSessionsMap.find(session_id) == sSessionsMap.end()) return false;  	delete (sSessionsMap[session_id]); @@ -297,16 +309,13 @@ bool LLIMModel::clearSession(LLUUID session_id)  	return true;  } -//*TODO remake it, instead of returing the list pass it as as parameter (IB) -std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index) +void LLIMModel::getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index)  { -	std::list<LLSD> return_list; -  	LLIMSession* session = findIMSession(session_id);  	if (!session)   	{  		llwarns << "session " << session_id << "does not exist " << llendl; -		return return_list; +		return;  	}  	int i = session->mMsgs.size() - start_index; @@ -317,7 +326,7 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)  	{  		LLSD msg;  		msg = *iter; -		return_list.push_back(*iter); +		messages.push_back(*iter);  		i--;  	} @@ -327,14 +336,9 @@ std::list<LLSD> LLIMModel::getMessages(LLUUID session_id, int start_index)  	arg["session_id"] = session_id;  	arg["num_unread"] = 0;  	mNoUnreadMsgsSignal(arg); - -    // TODO: in the future is there a more efficient way to return these -	//of course there is - return as parameter (IB) -	return return_list; -  } -bool LLIMModel::addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) {  +bool LLIMModel::addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text) {  	LLIMSession* session = findIMSession(session_id); @@ -383,8 +387,8 @@ bool LLIMModel::logToFile(const LLUUID& session_id, const std::string& from, con  	return false;  } -//*TODO add const qualifier and pass by references (IB) -bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text, bool log2file /* = true */) {  +bool LLIMModel::addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& from_id,  +						   const std::string& utf8_text, bool log2file /* = true */) {   	LLIMSession* session = findIMSession(session_id);  	if (!session)  @@ -506,7 +510,7 @@ void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id,  	gAgent.sendReliableMessage();  } -void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id)  +void LLIMModel::sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id)  {  	if(session_id.notNull())  	{ @@ -890,20 +894,11 @@ public:  		{  			gIMMgr->clearPendingAgentListUpdates(mSessionID);  			gIMMgr->clearPendingInvitation(mSessionID); - -			LLFloaterIMPanel* floaterp = -				gIMMgr->findFloaterBySession(mSessionID); - -			if ( floaterp ) +			if ( 404 == statusNum )  			{ -				if ( 404 == statusNum ) -				{ -					std::string error_string; -					error_string = "does not exist"; - -					floaterp->showSessionStartError( -						error_string); -				} +				std::string error_string; +				error_string = "does not exist"; +				gIMMgr->showSessionStartError(error_string, mSessionID);  			}  		}  	} @@ -955,6 +950,106 @@ LLUUID LLIMMgr::computeSessionID(  	return session_id;  } +inline LLFloater* getFloaterBySessionID(const LLUUID session_id) +{ +	LLFloater* floater = NULL; +	if ( gIMMgr ) +	{ +		floater = dynamic_cast < LLFloater* > +			( gIMMgr->findFloaterBySession(session_id) ); +	} +	if ( !floater ) +	{ +		floater = dynamic_cast < LLFloater* > +			( LLIMFloater::findInstance(session_id) ); +	} +	return floater; +} + +void +LLIMMgr::showSessionStartError( +	const std::string& error_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; +	args["REASON"] = LLTrans::getString(error_string); +	args["RECIPIENT"] = floater->getTitle(); + +	LLSD payload; +	payload["session_id"] = session_id; + +	LLNotifications::instance().add( +		"ChatterBoxSessionStartError", +		args, +		payload, +		LLIMMgr::onConfirmForceCloseError); +} + +void +LLIMMgr::showSessionEventError( +	const std::string& event_string, +	const std::string& error_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; +	args["REASON"] = +		LLTrans::getString(error_string); +	args["EVENT"] = +		LLTrans::getString(event_string); +	args["RECIPIENT"] = floater->getTitle(); + +	LLNotifications::instance().add( +		"ChatterBoxSessionEventError", +		args); +} + +void +LLIMMgr::showSessionForceClose( +	const std::string& reason_string, +	const LLUUID session_id) +{ +	const LLFloater* floater = getFloaterBySessionID (session_id); +	if (!floater) return; + +	LLSD args; + +	args["NAME"] = floater->getTitle(); +	args["REASON"] = LLTrans::getString(reason_string); + +	LLSD payload; +	payload["session_id"] = session_id; + +	LLNotifications::instance().add( +		"ForceCloseChatterBoxSession", +		args, +		payload, +		LLIMMgr::onConfirmForceCloseError); +} + +//static +bool +LLIMMgr::onConfirmForceCloseError( +	const LLSD& notification, +	const LLSD& response) +{ +	//only 1 option really +	LLUUID session_id = notification["payload"]["session_id"]; + +	LLFloater* floater = getFloaterBySessionID (session_id); +	if ( floater ) +	{ +		floater->closeFloater(FALSE); +	} +	return false; +} + +  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  // Class LLIncomingCallDialog  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1114,29 +1209,6 @@ void LLIncomingCallDialog::processCallResponse(S32 response)  	}  } -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLIMViewFriendObserver -// -// Bridge to suport knowing when the inventory has changed. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLIMViewFriendObserver : public LLFriendObserver -{ -public: -	LLIMViewFriendObserver(LLIMMgr* tv) : mTV(tv) {} -	virtual ~LLIMViewFriendObserver() {} -	virtual void changed(U32 mask) -	{ -		if(mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) -		{ -			mTV->refresh(); -		} -	} -protected: -	LLIMMgr* mTV; -}; - -  bool inviteUserResponse(const LLSD& notification, const LLSD& response)  {  	const LLSD& payload = notification["payload"]; @@ -1237,7 +1309,6 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response)  //  LLIMMgr::LLIMMgr() : -	mFriendObserver(NULL),  	mIMReceived(FALSE)  {  	static bool registered_dialog = false; @@ -1246,21 +1317,11 @@ LLIMMgr::LLIMMgr() :  		LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);  		registered_dialog = true;  	} -		 -	mFriendObserver = new LLIMViewFriendObserver(this); -	LLAvatarTracker::instance().addObserver(mFriendObserver);  	mPendingInvitations = LLSD::emptyMap();  	mPendingAgentListUpdates = LLSD::emptyMap();  } -LLIMMgr::~LLIMMgr() -{ -	LLAvatarTracker::instance().removeObserver(mFriendObserver); -	delete mFriendObserver; -	// Children all cleaned up by default view destructor. -} -  // Add a message to a session.   void LLIMMgr::addMessage(  	const LLUUID& session_id, @@ -1299,9 +1360,15 @@ void LLIMMgr::addMessage(  		fixed_session_name = session_name;  	} -	if (!LLIMModel::getInstance()->findIMSession(new_session_id)) +	bool new_session = !hasSession(session_id); +	if (new_session)  	{ -		LLIMModel::getInstance()->newSession(session_id, fixed_session_name, dialog, other_participant_id); +		// *NOTE dzaporozhan +		// Workaround for critical bug EXT-1918 + +		// *TODO  +		// Investigate cases when session_id == NULL and find solution to handle those cases +		LLIMModel::getInstance()->newSession(new_session_id, fixed_session_name, dialog, other_participant_id);  	}  	floater = findFloaterBySession(new_session_id); @@ -1318,15 +1385,16 @@ void LLIMMgr::addMessage(  	// create IM window as necessary  	if(!floater)  	{ - -		  		floater = createFloater(  			new_session_id,  			other_participant_id,  			fixed_session_name,  			dialog,  			FALSE); +	} +	if (new_session) +	{  		// When we get a new IM, and if you are a god, display a bit  		// of information about the source. This is to help liaisons  		// when answering questions. @@ -1336,7 +1404,7 @@ void LLIMMgr::addMessage(  			std::ostringstream bonus_info;  			bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " "  				<< parent_estate_id -			<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") +				<< ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "")  				<< ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : "");  			// once we have web-services (or something) which returns @@ -1439,10 +1507,7 @@ S32 LLIMMgr::getNumberOfUnreadIM()  	S32 num = 0;  	for(it = LLIMModel::sSessionsMap.begin(); it != LLIMModel::sSessionsMap.end(); ++it)  	{ -		if((*it).first != mBeingRemovedSessionID) -		{ -			num += (*it).second->mNumUnread; -		} +		num += (*it).second->mNumUnread;  	}  	return num; @@ -1458,15 +1523,6 @@ BOOL LLIMMgr::getIMReceived() const  	return mIMReceived;  } -// This method returns TRUE if the local viewer has a session -// currently open keyed to the uuid.  -BOOL LLIMMgr::isIMSessionOpen(const LLUUID& uuid) -{ -	LLFloaterIMPanel* floater = findFloaterBySession(uuid); -	if(floater) return TRUE; -	return FALSE; -} -  LLUUID LLIMMgr::addP2PSession(const std::string& name,  							const LLUUID& other_participant_id,  							const std::string& voice_session_handle, @@ -1560,41 +1616,25 @@ bool LLIMMgr::leaveSession(const LLUUID& session_id)  	return true;  } -// This removes the panel referenced by the uuid, and then restores -// internal consistency. The internal pointer is not deleted? Did you mean -// a pointer to the corresponding LLIMSession? Session data is cleared now. -// Put a copy of UUID to avoid problem when passed reference becames invalid -// if it has been come from the object removed in observer. -void LLIMMgr::removeSession(LLUUID session_id) +// Removes data associated with a particular session specified by session_id +void LLIMMgr::removeSession(const LLUUID& session_id)  { -	if (mBeingRemovedSessionID == session_id) -	{ -		return; -	} +	llassert_always(hasSession(session_id)); +	//*TODO remove this floater thing when Communicate Floater is being deleted (IB)  	LLFloaterIMPanel* floater = findFloaterBySession(session_id);  	if(floater)  	{  		mFloaters.erase(floater->getHandle());  		LLFloaterChatterBox::getInstance()->removeFloater(floater); -		//mTabContainer->removeTabPanel(floater); - -		clearPendingInvitation(session_id); -		clearPendingAgentListUpdates(session_id);  	} -	// for some purposes storing ID of a sessios that is being removed -	mBeingRemovedSessionID = session_id; -	notifyObserverSessionRemoved(session_id); +	clearPendingInvitation(session_id); +	clearPendingAgentListUpdates(session_id); -	//if we don't clear session data on removing the session -	//we can't use LLBottomTray as observer of session creation/delettion and  -	//creating chiclets only on session created even, we need to handle chiclets creation -	//the same way as LLFloaterIMPanels were managed.  	LLIMModel::getInstance()->clearSession(session_id); -	// now this session is completely removed -	mBeingRemovedSessionID.setNull(); +	notifyObserverSessionRemoved(session_id);  }  void LLIMMgr::inviteToSession( @@ -1723,10 +1763,6 @@ void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::stri  	}  } -void LLIMMgr::refresh() -{ -} -  void LLIMMgr::disconnectAllSessions()  {  	LLFloaterIMPanel* floater = NULL; @@ -2038,6 +2074,12 @@ void LLIMMgr::processIMTypingCore(const LLIMInfo* im_info, BOOL typing)  	{  		floater->processIMTyping(im_info, typing);  	} + +	LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +	if ( im_floater ) +	{ +		im_floater->processIMTyping(im_info, typing); +	}  }  class LLViewerChatterBoxSessionStartReply : public LLHTTPNode @@ -2087,19 +2129,21 @@ public:  				}  			} +			LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +			if ( im_floater ) +			{ +				if ( body.has("session_info") ) +				{ +					im_floater->processSessionUpdate(body["session_info"]); +				} +			} +  			gIMMgr->clearPendingAgentListUpdates(session_id);  		}  		else  		{ -			//throw an error dialog and close the temp session's -			//floater -			LLFloaterIMPanel* floater =  -				gIMMgr->findFloaterBySession(temp_session_id); - -			if ( floater ) -			{ -				floater->showSessionStartError(body["error"].asString()); -			} +			//throw an error dialog and close the temp session's floater +			gIMMgr->showSessionStartError(body["error"].asString(), temp_session_id);  		}  		gIMMgr->clearPendingAgentListUpdates(session_id); @@ -2132,15 +2176,10 @@ public:  		if ( !success )  		{  			//throw an error dialog -			LLFloaterIMPanel* floater =  -				gIMMgr->findFloaterBySession(session_id); - -			if (floater) -			{ -				floater->showSessionEventError( -					body["event"].asString(), -					body["error"].asString()); -			} +			gIMMgr->showSessionEventError( +				body["event"].asString(), +				body["error"].asString(), +				session_id);  		}  	}  }; @@ -2158,13 +2197,7 @@ public:  		session_id = input["body"]["session_id"].asUUID();  		reason = input["body"]["reason"].asString(); -		LLFloaterIMPanel* floater = -			gIMMgr ->findFloaterBySession(session_id); - -		if ( floater ) -		{ -			floater->showSessionForceClose(reason); -		} +		gIMMgr->showSessionForceClose(reason, session_id);  	}  }; @@ -2202,11 +2235,17 @@ public:  		const LLSD& context,  		const LLSD& input) const  	{ -		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(input["body"]["session_id"].asUUID()); +		LLUUID session_id = input["body"]["session_id"].asUUID(); +		LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(session_id);  		if (floaterp)  		{  			floaterp->processSessionUpdate(input["body"]["info"]);  		} +		LLIMFloater* im_floater = LLIMFloater::findInstance(session_id); +		if ( im_floater ) +		{ +			im_floater->processSessionUpdate(input["body"]["info"]); +		}  	}  }; diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index 68beb29034..ae8fd355ea 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -34,7 +34,7 @@  #define LL_LLIMVIEW_H  #include "lldarray.h" -#include "llfloateractivespeakers.h" //for LLIMSpeakerMgr +#include "llspeakers.h" //for LLIMSpeakerMgr  #include "llimpanel.h" //for voice channels  #include "llmodaldialog.h"  #include "llinstantmessage.h" @@ -70,6 +70,13 @@ public:  		LLIMSpeakerMgr* mSpeakers;  		bool mSessionInitialized; + +		//true if calling back the session URI after the session has closed is possible. +		//Currently this will be false only for PSTN P2P calls. +		bool mCallBackEnabled; + +		bool mTextIMPossible; +		bool mOtherParticipantIsAvatar;  	}; @@ -104,18 +111,35 @@ public:  	boost::signals2::connection addNewMsgCallback( session_callback_t cb ) { return mNewMsgSignal.connect(cb); }  	boost::signals2::connection addNoUnreadMsgsCallback( session_callback_t cb ) { return mNoUnreadMsgsSignal.connect(cb); } -	bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id,  +	/** +	 * Create new session object in a model +	 */ +	bool newSession(const LLUUID& session_id, const std::string& name, const EInstantMessage& type, const LLUUID& other_participant_id,   		const std::vector<LLUUID>& ids = std::vector<LLUUID>()); -	bool clearSession(LLUUID session_id); -	std::list<LLSD> getMessages(LLUUID session_id, int start_index = 0); -	bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text, bool log2file = true); -	bool addToHistory(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text);  +	/** +	 * Remove all session data associated with a session specified by session_id +	 */ +	bool clearSession(const LLUUID& session_id); -	bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text); +	/** +	 * Populate supplied std::list with messages starting from index specified by start_index +	 */ +	void getMessages(const LLUUID& session_id, std::list<LLSD>& messages, int start_index = 0); -	//used to get the name of the session, for use as the title -	//currently just the other avatar name +	/** +	 * Add a message to an IM Model - the message is saved in a message store associated with a session specified by session_id +	 * and also saved into a file if log2file is specified. +	 * It sends new message signal for each added message. +	 */ +	bool addMessage(const LLUUID& session_id, const std::string& from, const LLUUID& other_participant_id, const std::string& utf8_text, bool log2file = true); +	 +	/** +	 * Get a session's name.  +	 * For a P2P chat - it's an avatar's name,  +	 * For a group chat - it's a group's name +	 * For an ad-hoc chat - is received from the server and is in a from of "<Avatar's name> conference" +	 */  	const std::string& getName(const LLUUID& session_id) const;  	/**  @@ -150,7 +174,7 @@ public:  	*/  	LLIMSpeakerMgr* getSpeakerManager(const LLUUID& session_id) const; -	static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id); +	static void sendLeaveSession(const LLUUID& session_id, const LLUUID& other_participant_id);  	static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id,  						  const std::vector<LLUUID>& ids, EInstantMessage dialog);  	static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); @@ -158,6 +182,19 @@ public:  								const LLUUID& other_participant_id, EInstantMessage dialog);  	void testMessages(); + +private: +	 +	/** +	 * Add message to a list of message associated with session specified by session_id +	 */ +	bool addToHistory(const LLUUID& session_id, const std::string& from, const LLUUID& from_id, const std::string& utf8_text);  + +	/** +	 * Save an IM message into a file +	 */ +	//*TODO should also save uuid of a sender +	bool logToFile(const LLUUID& session_id, const std::string& from, const std::string& utf8_text);  };  class LLIMSessionObserver @@ -183,7 +220,7 @@ public:  	};  	LLIMMgr(); -	virtual ~LLIMMgr(); +	virtual ~LLIMMgr() {};  	// Add a message to a session. The session can keyed to sesion id  	// or agent id. @@ -200,11 +237,6 @@ public:  	void addSystemMessage(const LLUUID& session_id, const std::string& message_name, const LLSD& args); -	// This method returns TRUE if the local viewer has a session -	// currently open keyed to the uuid. The uuid can be keyed by -	// either session id or agent id. -	BOOL isIMSessionOpen(const LLUUID& uuid); -  	// This adds a session to the talk view. The name is the local  	// name of the session, dialog specifies the type of  	// session. Since sessions can be keyed off of first recipient or @@ -250,9 +282,6 @@ public:  	void processIMTypingStart(const LLIMInfo* im_info);  	void processIMTypingStop(const LLIMInfo* im_info); -	// Rebuild stuff -	void refresh(); -  	void notifyNewIM();  	void clearNewIMNotification(); @@ -268,10 +297,6 @@ public:  	// good connection.  	void disconnectAllSessions(); -	// This is a helper function to determine what kind of im session -	// should be used for the given agent. -	static EInstantMessage defaultIMTypeForAgent(const LLUUID& agent_id); -  	BOOL hasSession(const LLUUID& session_id);  	// This method returns the im panel corresponding to the uuid @@ -290,11 +315,18 @@ public:  	void clearPendingAgentListUpdates(const LLUUID& session_id);  	//HACK: need a better way of enumerating existing session, or listening to session create/destroy events +	//@deprecated, is used only by LLToolBox, which is not used anywhere, right? (IB)  	const std::set<LLHandle<LLFloater> >& getIMFloaterHandles() { return mFloaters; }  	void addSessionObserver(LLIMSessionObserver *);  	void removeSessionObserver(LLIMSessionObserver *); +	//show error statuses to the user +	void showSessionStartError(const std::string& error_string, const LLUUID session_id); +	void showSessionEventError(const std::string& event_string, const std::string& error_string, const LLUUID session_id); +	void showSessionForceClose(const std::string& reason, const LLUUID session_id); +	static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); +  	/**  	 * Start call in a session  	 * @return false if voice channel doesn't exist @@ -308,10 +340,11 @@ public:  	bool endCall(const LLUUID& session_id);  private: -	// This removes the panel referenced by the uuid, and then -	// restores internal consistency. The internal pointer is not -	// deleted. -	void removeSession(LLUUID session_id); + +	/** +	 * Remove data associated with a particular session specified by session_id +	 */ +	void removeSession(const LLUUID& session_id);  	// create a panel and update internal representation for  	// consistency. Returns the pointer, caller (the class instance @@ -340,8 +373,9 @@ private:  	void notifyObserverSessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id);  private: +	 +	//*TODO should be deleted when Communicate Floater is being deleted  	std::set<LLHandle<LLFloater> > mFloaters; -	LLFriendObserver* mFriendObserver;  	typedef std::list <LLIMSessionObserver *> session_observers_list_t;  	session_observers_list_t mSessionObservers; @@ -351,9 +385,6 @@ private:  	LLSD mPendingInvitations;  	LLSD mPendingAgentListUpdates; -	// ID of a session that is being removed: observers are already told -	// that this session is being removed, but it is still present in the sessions' map -	LLUUID	mBeingRemovedSessionID;  };  class LLIncomingCallDialog : public LLModalDialog diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp index b36b7cf50e..091346d3b4 100644 --- a/indra/newview/lllandmarkactions.cpp +++ b/indra/newview/lllandmarkactions.cpp @@ -348,7 +348,7 @@ LLLandmark* LLLandmarkActions::getLandmark(const LLUUID& landmarkInventoryItemID  {  	LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID);  	if (NULL == item) -		return false; +		return NULL;  	const LLUUID& asset_id = item->getAssetUUID();  	return gLandmarkList.getAsset(asset_id, NULL); diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h index d651259790..32f05e702b 100644 --- a/indra/newview/lllandmarkactions.h +++ b/indra/newview/lllandmarkactions.h @@ -108,7 +108,7 @@ public:      /**       * @brief Retrieve a landmark from gLandmarkList by inventory item's id       *  -     * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist. +     * @return pointer to loaded landmark from gLandmarkList or NULL if landmark does not exist or wasn't loaded.       */      static LLLandmark* getLandmark(const LLUUID& landmarkInventoryItemID); diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp index 3802d13f8b..c32ef2f22b 100644 --- a/indra/newview/llnavigationbar.cpp +++ b/indra/newview/llnavigationbar.cpp @@ -261,6 +261,15 @@ void LLNavigationBar::draw()  		onTeleportHistoryChanged();  		mPurgeTPHistoryItems = false;  	} + +	if (isBackgroundVisible()) +	{ +		static LLUICachedControl<S32> drop_shadow_floater ("DropShadowFloater", 0); +		static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); +		gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, +                           color_drop_shadow, drop_shadow_floater ); +	} +  	LLPanel::draw();  } diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp index 148f72703c..12638ab855 100644 --- a/indra/newview/llnearbychat.cpp +++ b/indra/newview/llnearbychat.cpp @@ -170,22 +170,6 @@ LLColor4 nearbychat_get_text_color(const LLChat& chat)  	return text_color;  } -std::string formatCurrentTime() -{ -	time_t utc_time; -	utc_time = time_corrected(); -	std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" -		+LLTrans::getString("TimeMin")+"] "; - -	LLSD substitution; - -	substitution["datetime"] = (S32) utc_time; -	LLStringUtil::format (timeStr, substitution); - -	return timeStr; -} - -  void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& color)  {  	S32 font_size = gSavedSettings.getS32("ChatFontSize"); @@ -210,16 +194,14 @@ void LLNearbyChat::add_timestamped_line(const LLChat& chat, const LLColor4& colo  	style_params.font(fontp);  	LLUUID uuid = chat.mFromID;  	std::string from = chat.mFromName; -	std::string time = formatCurrentTime();  	std::string message = chat.mText; -	mChatHistory->appendWidgetMessage(uuid, from, time, message, style_params); +	mChatHistory->appendWidgetMessage(chat, style_params);  }  void	LLNearbyChat::addMessage(const LLChat& chat)  {  	LLColor4 color = nearbychat_get_text_color(chat); -  	if (chat.mChatType == CHAT_TYPE_DEBUG_MSG)  	{  		if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE) diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp index 5fa97926a5..217007fb15 100644 --- a/indra/newview/llnearbychatbar.cpp +++ b/indra/newview/llnearbychatbar.cpp @@ -45,6 +45,7 @@  #include "llviewerstats.h"  #include "llcommandhandler.h"  #include "llviewercontrol.h" +#include "llnavigationbar.h"  S32 LLNearbyChatBar::sLastSpecialChatChannel = 0; @@ -177,6 +178,31 @@ void LLGestureComboBox::draw()  	LLComboBox::draw();  } +//virtual +void LLGestureComboBox::showList() +{ +	LLComboBox::showList(); + +	// Calculating amount of space between the navigation bar and gestures combo +	LLNavigationBar* nb = LLNavigationBar::getInstance(); +	S32 x, nb_bottom; +	nb->localPointToScreen(0, 0, &x, &nb_bottom); +	 +	S32 list_bottom; +	mList->localPointToScreen(0, 0, &x, &list_bottom); + +	S32 max_height = nb_bottom - list_bottom; + +	LLRect rect = mList->getRect(); +	// List overlapped navigation bar, downsize it +	if (rect.getHeight() > max_height)  +	{ +		rect.setOriginAndSize(rect.mLeft, rect.mBottom, rect.getWidth(), max_height); +		mList->setRect(rect); +		mList->reshape(rect.getWidth(), rect.getHeight()); +	} +} +  LLNearbyChatBar::LLNearbyChatBar()   	: LLPanel()  	, mChatBox(NULL) diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h index b902ff86cc..06204e6367 100644 --- a/indra/newview/llnearbychatbar.h +++ b/indra/newview/llnearbychatbar.h @@ -40,7 +40,7 @@  #include "llchiclet.h"  #include "llvoiceclient.h"  #include "lloutputmonitorctrl.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  class LLGestureComboBox  	: public LLComboBox @@ -62,6 +62,9 @@ public:  	virtual void changed() { refreshGestures(); }  protected: + +	virtual void showList(); +  	LLFrameTimer mGestureLabelTimer;  	std::vector<LLMultiGesture*> mGestures;  	std::string mLabel; diff --git a/indra/newview/llnotificationtiphandler.cpp b/indra/newview/llnotificationtiphandler.cpp index 7239f49b7f..543198c1d2 100644 --- a/indra/newview/llnotificationtiphandler.cpp +++ b/indra/newview/llnotificationtiphandler.cpp @@ -86,6 +86,20 @@ bool LLTipHandler::processNotification(const LLSD& notify)  	if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")  	{ +		// archive message in nearby chat +		LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); +		if(nearby_chat) +		{ +			LLChat chat_msg(notification->getMessage()); +			nearby_chat->addMessage(chat_msg); + +			// don't show toast if Nearby Chat is opened +			if (nearby_chat->getVisible()) +			{ +				return true; +			}			 +		} +  		LLToastNotifyPanel* notify_box = new LLToastNotifyPanel(notification);  		LLToast::Params p; @@ -99,14 +113,6 @@ bool LLTipHandler::processNotification(const LLSD& notify)  		LLScreenChannel* channel = dynamic_cast<LLScreenChannel*>(mChannel);  		if(channel)  			channel->addToast(p); - -		// archive message in nearby chat -		LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance<LLNearbyChat>("nearby_chat", LLSD()); -		if(nearby_chat) -		{ -			LLChat chat_msg(notification->getMessage()); -			nearby_chat->addMessage(chat_msg); -		}  	}  	else if (notify["sigtype"].asString() == "delete")  	{ diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 6eed956eb8..f9eeaf1e9e 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -34,6 +34,7 @@  #include "llpanelimcontrolpanel.h" +#include "llagent.h"  #include "llavataractions.h"  #include "llavatariconctrl.h"  #include "llbutton.h" @@ -41,6 +42,53 @@  #include "llavatarlist.h"  #include "llparticipantlist.h"  #include "llimview.h" +#include "llvoicechannel.h" + +void LLPanelChatControlPanel::onCallButtonClicked() +{ +	gIMMgr->startCall(mSessionId); +} + +void LLPanelChatControlPanel::onEndCallButtonClicked() +{ +	gIMMgr->endCall(mSessionId); +} + +BOOL LLPanelChatControlPanel::postBuild() +{ +	childSetAction("call_btn", boost::bind(&LLPanelChatControlPanel::onCallButtonClicked, this)); +	childSetAction("end_call_btn", boost::bind(&LLPanelChatControlPanel::onEndCallButtonClicked, this)); + +	return TRUE; +} + +void LLPanelChatControlPanel::draw() +{ +	// hide/show start call and end call buttons +	bool voice_enabled = LLVoiceClient::voiceEnabled(); + +	LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(mSessionId); +	if (!session) return; + +	LLVoiceChannel* voice_channel = session->mVoiceChannel; +	if (voice_channel && voice_enabled) +	{ +		childSetVisible("end_call_btn", voice_channel->getState() >= LLVoiceChannel::STATE_CALL_STARTED); +		childSetVisible("call_btn", voice_channel->getState() < LLVoiceChannel::STATE_CALL_STARTED); +	} + +	bool session_initialized = session->mSessionInitialized; +	bool callback_enabled = session->mCallBackEnabled; +	LLViewerRegion* region = gAgent.getRegion(); + +	BOOL enable_connect = (region && region->getCapability("ChatSessionRequest") != "") +		&& session_initialized +		&& voice_enabled +		&& callback_enabled; +	childSetEnabled("call_btn", enable_connect); + +	LLPanel::draw(); +}  LLPanelIMControlPanel::LLPanelIMControlPanel()  { @@ -54,11 +102,11 @@ BOOL LLPanelIMControlPanel::postBuild()  {  	childSetAction("view_profile_btn", boost::bind(&LLPanelIMControlPanel::onViewProfileButtonClicked, this));  	childSetAction("add_friend_btn", boost::bind(&LLPanelIMControlPanel::onAddFriendButtonClicked, this)); -	childSetAction("call_btn", boost::bind(&LLPanelIMControlPanel::onCallButtonClicked, this)); +  	childSetAction("share_btn", boost::bind(&LLPanelIMControlPanel::onShareButtonClicked, this));  	childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(getChild<LLAvatarIconCtrl>("avatar_icon")->getAvatarId())); - -	return TRUE; +	 +	return LLPanelChatControlPanel::postBuild();  }  void LLPanelIMControlPanel::onViewProfileButtonClicked() @@ -73,22 +121,29 @@ void LLPanelIMControlPanel::onAddFriendButtonClicked()  	LLAvatarActions::requestFriendshipDialog(avatar_icon->getAvatarId(), full_name);  } -void LLPanelIMControlPanel::onCallButtonClicked() -{ -	// *TODO: Implement -} -  void LLPanelIMControlPanel::onShareButtonClicked()  {  	// *TODO: Implement  } -void LLPanelIMControlPanel::setID(const LLUUID& avatar_id) +void LLPanelIMControlPanel::setSessionId(const LLUUID& session_id)  { +	LLPanelChatControlPanel::setSessionId(session_id); + +	LLIMModel& im_model = LLIMModel::instance(); + +	LLUUID avatar_id = im_model.getOtherParticipantID(session_id); +  	// Disable "Add friend" button for friends.  	childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(avatar_id));  	getChild<LLAvatarIconCtrl>("avatar_icon")->setValue(avatar_id); + +	// Disable profile button if participant is not realy SL avatar +	LLIMModel::LLIMSession* im_session = +		im_model.findIMSession(session_id); +	if( im_session && !im_session->mOtherParticipantIsAvatar ) +		childSetEnabled("view_profile_btn", FALSE);  } @@ -100,12 +155,11 @@ LLPanelGroupControlPanel::LLPanelGroupControlPanel(const LLUUID& session_id)  BOOL LLPanelGroupControlPanel::postBuild()  {  	childSetAction("group_info_btn", boost::bind(&LLPanelGroupControlPanel::onGroupInfoButtonClicked, this)); -	childSetAction("call_btn", boost::bind(&LLPanelGroupControlPanel::onCallButtonClicked, this));  	mAvatarList = getChild<LLAvatarList>("speakers_list");  	mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList); -	return TRUE; +	return LLPanelChatControlPanel::postBuild();  }  LLPanelGroupControlPanel::~LLPanelGroupControlPanel() @@ -127,13 +181,23 @@ void LLPanelGroupControlPanel::onGroupInfoButtonClicked()  } -void LLPanelGroupControlPanel::onCallButtonClicked() +void LLPanelGroupControlPanel::setSessionId(const LLUUID& session_id)  { -	// *TODO: Implement +	LLPanelChatControlPanel::setSessionId(session_id); + +	mGroupID = LLIMModel::getInstance()->getOtherParticipantID(session_id);  } -void LLPanelGroupControlPanel::setID(const LLUUID& id) +LLPanelAdHocControlPanel::LLPanelAdHocControlPanel(const LLUUID& session_id):LLPanelGroupControlPanel(session_id) +{ +} + +BOOL LLPanelAdHocControlPanel::postBuild()  { -	mGroupID = id; +	mAvatarList = getChild<LLAvatarList>("speakers_list"); +	mParticipantList = new LLParticipantList(mSpeakerManager, mAvatarList); + +	return LLPanelChatControlPanel::postBuild();  } + diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h index 138b1630c4..220b7b14ba 100644 --- a/indra/newview/llpanelimcontrolpanel.h +++ b/indra/newview/llpanelimcontrolpanel.h @@ -45,8 +45,16 @@ public:  	LLPanelChatControlPanel() {};  	~LLPanelChatControlPanel() {}; -	// sets the group or avatar UUID -	virtual void setID(const LLUUID& avatar_id)= 0; +	virtual BOOL postBuild(); +	virtual void draw(); + +	void onCallButtonClicked(); +	void onEndCallButtonClicked(); + +	virtual void setSessionId(const LLUUID& session_id) { mSessionId = session_id; } + +private: +	LLUUID mSessionId;  }; @@ -58,13 +66,14 @@ public:  	BOOL postBuild(); -	void setID(const LLUUID& avatar_id); +	void setSessionId(const LLUUID& session_id);  private:  	void onViewProfileButtonClicked();  	void onAddFriendButtonClicked(); -	void onCallButtonClicked();  	void onShareButtonClicked(); + +	LLUUID mAvatarID;  }; @@ -76,19 +85,26 @@ public:  	BOOL postBuild(); -	void setID(const LLUUID& id); +	void setSessionId(const LLUUID& session_id);  	/*virtual*/ void draw(); -private: -	void onGroupInfoButtonClicked(); -	void onCallButtonClicked(); - +protected:  	LLUUID mGroupID;  	LLSpeakerMgr* mSpeakerManager;  	LLAvatarList* mAvatarList;  	LLParticipantList* mParticipantList; + +private: +	void onGroupInfoButtonClicked();  }; +class LLPanelAdHocControlPanel : public LLPanelGroupControlPanel +{ +public: +	LLPanelAdHocControlPanel(const LLUUID& session_id); + +	BOOL postBuild(); +};  #endif // LL_LLPANELIMCONTROLPANEL_H diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp index 83fb147a49..3d0db71045 100644 --- a/indra/newview/llpanellandmarks.cpp +++ b/indra/newview/llpanellandmarks.cpp @@ -38,10 +38,12 @@  #include "llsdutil.h"  #include "llsdutil_math.h" +#include "llaccordionctrl.h"  #include "llaccordionctrltab.h"  #include "llagent.h"  #include "llagentpicksinfo.h"  #include "llagentui.h" +#include "llcallbacklist.h"  #include "lldndbutton.h"  #include "llfloaterworldmap.h"  #include "llfolderviewitem.h" @@ -56,7 +58,7 @@  //static LLRegisterPanelClassWrapper<LLLandmarksPanel> t_landmarks("panel_landmarks");  static const std::string OPTIONS_BUTTON_NAME = "options_gear_btn"; -static const std::string ADD_LANDMARK_BUTTON_NAME = "add_landmark_btn"; +static const std::string ADD_BUTTON_NAME = "add_btn";  static const std::string ADD_FOLDER_BUTTON_NAME = "add_folder_btn";  static const std::string TRASH_BUTTON_NAME = "trash_btn"; @@ -75,6 +77,7 @@ LLLandmarksPanel::LLLandmarksPanel()  	,	mListCommands(NULL)  	,	mGearFolderMenu(NULL)  	,	mGearLandmarkMenu(NULL) +	,	mDirtyFilter(false)  {  	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml");  } @@ -98,16 +101,37 @@ BOOL LLLandmarksPanel::postBuild()  	initMyInventroyPanel();  	initLibraryInventroyPanel(); +	gIdleCallbacks.addFunction(LLLandmarksPanel::doIdle, this);  	return TRUE;  }  // virtual  void LLLandmarksPanel::onSearchEdit(const std::string& string)  { +	static std::string prev_string(""); + +	if (prev_string == string) return; + +	// show all folders in Landmarks Accordion for empty filter +	mLandmarksInventoryPanel->setShowFolderState(string.empty() ? +		LLInventoryFilter::SHOW_ALL_FOLDERS : +		LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS +		); +  	filter_list(mFavoritesInventoryPanel, string);  	filter_list(mLandmarksInventoryPanel, string);  	filter_list(mMyInventoryPanel, string);  	filter_list(mLibraryInventoryPanel, string); + +	prev_string = string; +	mDirtyFilter = true; + +	// give FolderView a chance to be refreshed. So, made all accordions visible +	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) +	{ +		LLAccordionCtrlTab* tab = *iter; +		tab->setVisible(true); +	}  }  // virtual @@ -300,6 +324,8 @@ void LLLandmarksPanel::processParcelInfo(const LLParcelData& parcel_data)  					panel_pick, panel_places,params));  			panel_pick->setSaveCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this,  				panel_pick, panel_places,params)); +			panel_pick->setCancelCallback(boost::bind(&LLLandmarksPanel::onPickPanelExit,this, +							panel_pick, panel_places,params));  		}  	}  } @@ -389,6 +415,7 @@ void LLLandmarksPanel::initLandmarksPanel(LLInventorySubTreePanel* inventory_lis  void LLLandmarksPanel::initAccordion(const std::string& accordion_tab_name, LLInventorySubTreePanel* inventory_list)  {  	LLAccordionCtrlTab* accordion_tab = getChild<LLAccordionCtrlTab>(accordion_tab_name); +	mAccordionTabs.push_back(accordion_tab);  	accordion_tab->setDropDownStateChangedCallback(  		boost::bind(&LLLandmarksPanel::onAccordionExpandedCollapsed, this, _2, inventory_list));  } @@ -433,11 +460,11 @@ void LLLandmarksPanel::initListCommandsHandlers()  	mListCommands = getChild<LLPanel>("bottom_panel");  	mListCommands->childSetAction(OPTIONS_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onActionsButtonClick, this)); -	mListCommands->childSetAction(ADD_LANDMARK_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddLandmarkButtonClick, this)); -	mListCommands->childSetAction(ADD_FOLDER_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddFolderButtonClick, this));  	mListCommands->childSetAction(TRASH_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onTrashButtonClick, this)); +	mListCommands->getChild<LLButton>(ADD_BUTTON_NAME)->setHeldDownCallback(boost::bind(&LLLandmarksPanel::onAddButtonHeldDown, this)); +	static const LLSD add_landmark_command("add_landmark"); +	mListCommands->childSetAction(ADD_BUTTON_NAME, boost::bind(&LLLandmarksPanel::onAddAction, this, add_landmark_command)); -	  	LLDragAndDropButton* trash_btn = mListCommands->getChild<LLDragAndDropButton>(TRASH_BUTTON_NAME);  	trash_btn->setDragAndDropHandler(boost::bind(&LLLandmarksPanel::handleDragAndDropToTrash, this  			,	_4 // BOOL drop @@ -453,6 +480,7 @@ void LLLandmarksPanel::initListCommandsHandlers()  	mEnableCallbackRegistrar.add("Places.LandmarksGear.Enable", boost::bind(&LLLandmarksPanel::isActionEnabled, this, _2));  	mGearLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  	mGearFolderMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_places_gear_folder.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); +	mMenuAdd = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_place_add_button.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());  } @@ -488,52 +516,26 @@ void LLLandmarksPanel::onActionsButtonClick()  		mGearFolderMenu->getChild<LLMenuItemCallGL>("collapse")->setVisible(cur_item->isOpen());  		menu = mGearFolderMenu;  	} -	if(menu) -	{ -		menu->buildDrawLabels(); -		menu->updateParent(LLMenuGL::sMenuContainer); -		LLView* actions_btn  = getChild<LLView>(OPTIONS_BUTTON_NAME); -		S32 menu_x, menu_y; -		actions_btn->localPointToOtherView(0,actions_btn->getRect().getHeight(),&menu_x,&menu_y, this); -		menu_y += menu->getRect().getHeight(); -		LLMenuGL::showPopup(this, menu, menu_x,menu_y); -	} +	showActionMenu(menu,OPTIONS_BUTTON_NAME);  } -void LLLandmarksPanel::onAddLandmarkButtonClick() const +void LLLandmarksPanel::onAddButtonHeldDown()  { -	if(LLLandmarkActions::landmarkAlreadyExists()) -	{ -		std::string location; -		LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL); -		llwarns<<" Landmark already exists at location:  "<< location<<llendl; -		return; -	} -	LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); +	showActionMenu(mMenuAdd,ADD_BUTTON_NAME);  } -void LLLandmarksPanel::onAddFolderButtonClick() const +void LLLandmarksPanel::showActionMenu(LLMenuGL* menu, std::string spawning_view_name)  { -	LLFolderViewItem*  item = getCurSelectedItem(); -	if(item &&  mCurrentSelectedList == mLandmarksInventoryPanel) +	if (menu)  	{ -		LLFolderViewEventListener* folder_bridge = NULL; -		if(item-> getListener()->getInventoryType() == LLInventoryType::IT_LANDMARK) -		{ -			// for a landmark get parent folder bridge -			folder_bridge = item->getParentFolder()->getListener(); -		} -		else if (item-> getListener()->getInventoryType() == LLInventoryType::IT_CATEGORY)  -		{ -			// for a folder get its own bridge -			folder_bridge = item->getListener(); -		} - -		menu_create_inventory_item(mCurrentSelectedList->getRootFolder() -			, dynamic_cast<LLFolderBridge*>(folder_bridge) -			, LLSD("category") -			, gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK) -			); +		menu->buildDrawLabels(); +		menu->updateParent(LLMenuGL::sMenuContainer); +		LLView* spawning_view = getChild<LLView> (spawning_view_name); +		S32 menu_x, menu_y; +		//show menu in co-ordinates of panel +		spawning_view->localPointToOtherView(0, spawning_view->getRect().getHeight(), &menu_x, &menu_y, this); +		menu_y += menu->getRect().getHeight(); +		LLMenuGL::showPopup(this, menu, menu_x, menu_y);  	}  } @@ -547,11 +549,39 @@ void LLLandmarksPanel::onAddAction(const LLSD& userdata) const  	std::string command_name = userdata.asString();  	if("add_landmark" == command_name)  	{ -		onAddLandmarkButtonClick(); +		if(LLLandmarkActions::landmarkAlreadyExists()) +		{ +			std::string location; +			LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_FULL); +			llwarns<<" Landmark already exists at location:  "<< location<<llendl; +			return; +		} +		LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark"));  	}   	else if ("category" == command_name)  	{ -		onAddFolderButtonClick(); +		LLFolderViewItem* item = getCurSelectedItem(); +		if (item && mCurrentSelectedList == mLandmarksInventoryPanel) +		{ +			LLFolderViewEventListener* folder_bridge = NULL; +			if (item-> getListener()->getInventoryType() +					== LLInventoryType::IT_LANDMARK) +			{ +				// for a landmark get parent folder bridge +				folder_bridge = item->getParentFolder()->getListener(); +			} +			else if (item-> getListener()->getInventoryType() +					== LLInventoryType::IT_CATEGORY) +			{ +				// for a folder get its own bridge +				folder_bridge = item->getListener(); +			} + +			menu_create_inventory_item(mCurrentSelectedList->getRootFolder(), +					dynamic_cast<LLFolderBridge*> (folder_bridge), LLSD( +							"category"), gInventory.findCategoryUUIDForType( +							LLAssetType::AT_LANDMARK)); +		}  	}  } @@ -854,6 +884,43 @@ bool LLLandmarksPanel::handleDragAndDropToTrash(BOOL drop, EDragAndDropType carg  } +void LLLandmarksPanel::doIdle(void* landmarks_panel) +{ +	LLLandmarksPanel* panel = (LLLandmarksPanel* ) landmarks_panel; + +	if (panel->mDirtyFilter) +	{ +		panel->updateFilteredAccordions(); +	} + +} + +void LLLandmarksPanel::updateFilteredAccordions() +{ +	LLInventoryPanel* inventory_list = NULL; +	LLAccordionCtrlTab* accordion_tab = NULL; +	for (accordion_tabs_t::const_iterator iter = mAccordionTabs.begin(); iter != mAccordionTabs.end(); ++iter) +	{ +		accordion_tab = *iter; +		inventory_list = dynamic_cast<LLInventorySubTreePanel*> (accordion_tab->getAccordionView()); +		if (NULL == inventory_list) continue; +		LLFolderView* fv = inventory_list->getRootFolder(); + +		bool has_visible_children = fv->hasVisibleChildren(); + +		accordion_tab->setVisible(has_visible_children); +	} + +	// we have to arrange accordion tabs for cases when filter string is less restrictive but  +	// all items are still filtered. +	static LLAccordionCtrl* accordion = getChild<LLAccordionCtrl>("landmarks_accordion"); +	accordion->arrange(); + +	// now filter state is applied to accordion tabs +	mDirtyFilter = false; +} + +  //////////////////////////////////////////////////////////////////////////  // HELPER FUNCTIONS  ////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h index 47c9f7647c..0e7abb4865 100644 --- a/indra/newview/llpanellandmarks.h +++ b/indra/newview/llpanellandmarks.h @@ -41,6 +41,7 @@  #include "llpanelpick.h"  #include "llremoteparcelrequest.h" +class LLAccordionCtrlTab;  class LLFolderViewItem;  class LLMenuGL;  class LLInventoryPanel; @@ -90,8 +91,8 @@ private:  	void initListCommandsHandlers();  	void updateListCommands();  	void onActionsButtonClick(); -	void onAddLandmarkButtonClick() const; -	void onAddFolderButtonClick() const; +	void showActionMenu(LLMenuGL* menu, std::string spawning_view_name); +	void onAddButtonHeldDown();  	void onTrashButtonClick() const;  	void onAddAction(const LLSD& command_name) const;  	void onClipboardAction(const LLSD& command_name) const; @@ -114,6 +115,18 @@ private:  	 */  	bool handleDragAndDropToTrash(BOOL drop, EDragAndDropType cargo_type, EAcceptance* accept); +	/** +	 * Static callback for gIdleCallbacks to perform actions out of drawing +	 */ +	static void doIdle(void* landmarks_panel); + +	/** +	 * Updates accordions according to filtered items in lists. +	 * +	 * It hides accordion for empty lists +	 */ +	void updateFilteredAccordions(); +  private:  	LLInventorySubTreePanel*	mFavoritesInventoryPanel;  	LLInventorySubTreePanel*	mLandmarksInventoryPanel; @@ -121,10 +134,15 @@ private:  	LLInventorySubTreePanel*	mLibraryInventoryPanel;  	LLMenuGL*					mGearLandmarkMenu;  	LLMenuGL*					mGearFolderMenu; +	LLMenuGL*					mMenuAdd;  	LLInventorySubTreePanel*	mCurrentSelectedList;  	LLPanel*					mListCommands;  	bool 						mSortByDate; +	bool						mDirtyFilter; +	 +	typedef	std::vector<LLAccordionCtrlTab*> accordion_tabs_t; +	accordion_tabs_t			mAccordionTabs;  };  #endif //LL_LLPANELLANDMARKS_H diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 61d66873ea..4580eeb336 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -413,13 +413,17 @@ BOOL LLPanelPeople::postBuild()  	mOnlineFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_online");  	mAllFriendList = getChild<LLPanel>(FRIENDS_TAB_NAME)->getChild<LLAvatarList>("avatars_all");  	mOnlineFriendList->setNoItemsCommentText(getString("no_friends_online")); +	mOnlineFriendList->setShowIcons("FriendsListShowIcons");  	mAllFriendList->setNoItemsCommentText(getString("no_friends")); +	mAllFriendList->setShowIcons("FriendsListShowIcons");  	mNearbyList = getChild<LLPanel>(NEARBY_TAB_NAME)->getChild<LLAvatarList>("avatar_list");  	mNearbyList->setNoItemsCommentText(getString("no_one_near")); +	mNearbyList->setShowIcons("NearbyListShowIcons");  	mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");  	mRecentList->setNoItemsCommentText(getString("no_people")); +	mRecentList->setShowIcons("RecentListShowIcons");  	mGroupList = getChild<LLGroupList>("group_list");  	mGroupList->setNoItemsCommentText(getString("no_groups")); @@ -611,6 +615,10 @@ void LLPanelPeople::updateButtons()  	bool recent_tab_active	= (cur_tab == RECENT_TAB_NAME);  	LLUUID selected_id; +	std::vector<LLUUID> selected_uuids; +	getCurrentItemIDs(selected_uuids); +	bool item_selected = (selected_uuids.size() == 1); +  	buttonSetVisible("group_info_btn",		group_tab_active);  	buttonSetVisible("chat_btn",			group_tab_active);  	buttonSetVisible("add_friend_btn",		nearby_tab_active || recent_tab_active); @@ -621,7 +629,6 @@ void LLPanelPeople::updateButtons()  	if (group_tab_active)  	{ -		bool item_selected = mGroupList->getSelectedItem() != NULL;  		bool cur_group_active = true;  		if (item_selected) @@ -629,7 +636,7 @@ void LLPanelPeople::updateButtons()  			selected_id = mGroupList->getSelectedUUID();  			cur_group_active = (gAgent.getGroupID() == selected_id);  		} -	 +  		LLPanel* groups_panel = mTabContainer->getCurrentPanel();  		groups_panel->childSetEnabled("activate_btn",	item_selected && !cur_group_active); // "none" or a non-active group selected  		groups_panel->childSetEnabled("plus_btn",		item_selected); @@ -640,18 +647,18 @@ void LLPanelPeople::updateButtons()  		bool is_friend = true;  		// Check whether selected avatar is our friend. -		if ((selected_id = getCurrentItemID()).notNull()) +		if (item_selected)  		{ +			selected_id = selected_uuids.front();  			is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL;  		}  		childSetEnabled("add_friend_btn",	!is_friend);  	} -	bool item_selected = selected_id.notNull();  	buttonSetEnabled("teleport_btn",		friends_tab_active && item_selected);  	buttonSetEnabled("view_profile_btn",	item_selected); -	buttonSetEnabled("im_btn",				item_selected); +	buttonSetEnabled("im_btn",				(selected_uuids.size() >= 1)); // allow starting the friends conference for multiple selection  	buttonSetEnabled("call_btn",			item_selected && false); // not implemented yet  	buttonSetEnabled("share_btn",			item_selected && false); // not implemented yet  	buttonSetEnabled("group_info_btn",		item_selected); @@ -877,7 +884,17 @@ void LLPanelPeople::onAddFriendWizButtonClicked()  void LLPanelPeople::onDeleteFriendButtonClicked()  { -	LLAvatarActions::removeFriendDialog(getCurrentItemID()); +	std::vector<LLUUID> selected_uuids; +	getCurrentItemIDs(selected_uuids); + +	if (selected_uuids.size() == 1) +	{ +		LLAvatarActions::removeFriendDialog( selected_uuids.front() ); +	} +	else if (selected_uuids.size() > 1) +	{ +		LLAvatarActions::removeFriendsDialog( selected_uuids ); +	}  }  void LLPanelPeople::onGroupInfoButtonClicked() @@ -963,6 +980,8 @@ void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ +		mAllFriendList->toggleIcons(); +		mOnlineFriendList->toggleIcons();  	}  	else if (chosen_item == "organize_offline")  	{ @@ -992,6 +1011,7 @@ void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ +		mNearbyList->toggleIcons();  	}  	else if (chosen_item == "sort_distance")  	{ @@ -1011,7 +1031,7 @@ void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata)  	}  	else if (chosen_item == "view_icons")  	{ -		// *TODO: implement showing/hiding icons +		mRecentList->toggleIcons();  	}  } diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp index cb9f7184f0..5af27a5ec1 100644 --- a/indra/newview/llpanelplaceinfo.cpp +++ b/indra/newview/llpanelplaceinfo.cpp @@ -55,6 +55,8 @@  #include "llagent.h"  #include "llagentui.h"  #include "llavatarpropertiesprocessor.h" +#include "llcallbacklist.h" +#include "llexpandabletextbox.h"  #include "llfloaterworldmap.h"  #include "llfloaterbuycurrency.h"  #include "llinventorymodel.h" @@ -65,6 +67,7 @@  #include "llviewerinventory.h"  #include "llviewerparcelmgr.h"  #include "llviewerregion.h" +#include "llviewercontrol.h"   #include "llviewertexteditor.h"  #include "llworldmap.h"  #include "llsdutil_math.h" @@ -76,7 +79,6 @@  typedef std::pair<LLUUID, std::string> folder_pair_t;  static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); -static std::string getFullFolderName(const LLViewerInventoryCategory* cat);  static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats);  static LLRegisterPanelClassWrapper<LLPanelPlaceInfo> t_place_info("panel_place_info"); @@ -111,7 +113,7 @@ BOOL LLPanelPlaceInfo::postBuild()  	mForSalePanel = getChild<LLPanel>("for_sale_panel");  	mYouAreHerePanel = getChild<LLPanel>("here_panel"); -	LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLPanelPlaceInfo::updateYouAreHereBanner,this)); +	gIdleCallbacks.addFunction(&LLPanelPlaceInfo::updateYouAreHereBanner, this);  	//Icon value should contain sale price of last selected parcel.   	mForSalePanel->getChild<LLIconCtrl>("icon_for_sale")-> @@ -120,7 +122,7 @@ BOOL LLPanelPlaceInfo::postBuild()  	mSnapshotCtrl = getChild<LLTextureCtrl>("logo");  	mRegionName = getChild<LLTextBox>("region_title");  	mParcelName = getChild<LLTextBox>("parcel_title"); -	mDescEditor = getChild<LLTextEditor>("description"); +	mDescEditor = getChild<LLExpandableTextBox>("description");  	mMaturityRatingText = getChild<LLTextBox>("maturity_value");  	mParcelOwner = getChild<LLTextBox>("owner_value"); @@ -456,13 +458,13 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)  		mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id);  	} -	if(!parcel_data.name.empty()) +	if(!parcel_data.sim_name.empty())  	{ -		mParcelName->setText(parcel_data.name); +		mRegionName->setText(parcel_data.sim_name);  	}  	else  	{ -		mParcelName->setText(LLStringUtil::null); +		mRegionName->setText(LLStringUtil::null);  	}  	if(!parcel_data.desc.empty()) @@ -509,19 +511,22 @@ void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data)  		region_z = llround(mPosRegion.mV[VZ]);  	} -	std::string name = getString("not_available"); -	if (!parcel_data.sim_name.empty()) +	if (!parcel_data.name.empty())  	{ -		name = llformat("%s (%d, %d, %d)", -						parcel_data.sim_name.c_str(), region_x, region_y, region_z); -		mRegionName->setText(name); +		mParcelName->setText(llformat("%s (%d, %d, %d)", +							 parcel_data.name.c_str(), region_x, region_y, region_z)); +	} +	else +	{ +		mParcelName->setText(getString("not_available"));  	}  	if (mInfoType == CREATE_LANDMARK)  	{  		if (parcel_data.name.empty())  		{ -			mTitleEditor->setText(name); +			mTitleEditor->setText(llformat("%s (%d, %d, %d)", +								  parcel_data.sim_name.c_str(), region_x, region_y, region_z));  		}  		else  		{ @@ -610,6 +615,9 @@ void LLPanelPlaceInfo::displaySelectedParcelInfo(LLParcel* parcel,  	parcel_data.name = parcel->getName();  	parcel_data.sim_name = region->getName();  	parcel_data.snapshot_id = parcel->getSnapshotID(); +	mPosRegion.setVec((F32)fmod(pos_global.mdV[VX], (F64)REGION_WIDTH_METERS), +					  (F32)fmod(pos_global.mdV[VY], (F64)REGION_WIDTH_METERS), +					  (F32)pos_global.mdV[VZ]);  	parcel_data.global_x = pos_global.mdV[VX];  	parcel_data.global_y = pos_global.mdV[VY];  	parcel_data.global_z = pos_global.mdV[VZ]; @@ -986,18 +994,22 @@ void LLPanelPlaceInfo::populateFoldersList()  		mFolderCombo->add(it->second, LLSD(it->first));  } -void LLPanelPlaceInfo::updateYouAreHereBanner() +//static +void LLPanelPlaceInfo::updateYouAreHereBanner(void* userdata)  {  	//YouAreHere Banner should be displayed only for selected places,   	// If you want to display it for landmark or teleport history item, you should check by mParcelId -	bool is_you_are_here = false; -	if (mSelectedParcelID != S32(-1) && !mLastSelectedRegionID.isNull()) -	{ -		is_you_are_here = gAgent.getRegion()->getRegionID()== mLastSelectedRegionID && -		mSelectedParcelID == LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); -	} -	mYouAreHerePanel->setVisible(is_you_are_here); +	LLPanelPlaceInfo* self  = static_cast<LLPanelPlaceInfo*>(userdata); +	if(!self->getVisible()) +		return; + +	static F32 radius  = gSavedSettings.getF32("YouAreHereDistance"); + +	BOOL display_banner = self->mLastSelectedRegionID == gAgent.getRegion()->getRegionID() &&  +			LLAgentUI::checkAgentDistance(self->mPosRegion, radius); + +	self->mYouAreHerePanel->setVisible(display_banner);  }  void LLPanelPlaceInfo::onForSaleBannerClick() @@ -1028,14 +1040,9 @@ void LLPanelPlaceInfo::onForSaleBannerClick()  } -  - -static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) -{ -	return left.second < right.second; -} -static std::string getFullFolderName(const LLViewerInventoryCategory* cat) +/*static*/ +std::string LLPanelPlaceInfo::getFullFolderName(const LLViewerInventoryCategory* cat)  {  	std::string name = cat->getName();  	LLUUID parent_id; @@ -1057,6 +1064,11 @@ static std::string getFullFolderName(const LLViewerInventoryCategory* cat)  	return name;  } +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) +{ +	return left.second < right.second; +} +  static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats)  {  	LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h index 7b3a8f050b..07a2434d59 100644 --- a/indra/newview/llpanelplaceinfo.h +++ b/indra/newview/llpanelplaceinfo.h @@ -43,6 +43,7 @@  class LLButton;  class LLComboBox; +class LLExpandableTextBox;  class LLInventoryItem;  class LLLineEditor;  class LLPanelPickEdit; @@ -52,6 +53,7 @@ class LLTextBox;  class LLTextEditor;  class LLTextureCtrl;  class LLViewerRegion; +class LLViewerInventoryCategory;  class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver  { @@ -131,11 +133,13 @@ public:  	/*virtual*/ void processParcelInfo(const LLParcelData& parcel_data);  	/*virtual*/ void handleVisibilityChange (BOOL new_visibility); +	 +	 static std::string getFullFolderName(const LLViewerInventoryCategory* cat);  private:  	void populateFoldersList(); -	void updateYouAreHereBanner(); +	static void updateYouAreHereBanner(void*);// added to gIdleCallbacks  	void onForSaleBannerClick();  	/** @@ -161,7 +165,7 @@ private:  	LLTextureCtrl*		mSnapshotCtrl;  	LLTextBox*			mRegionName;  	LLTextBox*			mParcelName; -	LLTextEditor*		mDescEditor; +	LLExpandableTextBox*mDescEditor;  	LLTextBox*			mMaturityRatingText;  	LLTextBox*			mParcelOwner;  	LLTextBox*			mLastVisited; diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp index 5ab823b6e5..b2e9110e96 100644 --- a/indra/newview/llpanelplaces.cpp +++ b/indra/newview/llpanelplaces.cpp @@ -351,7 +351,16 @@ void LLPanelPlaces::setItem(LLInventoryItem* item)  	if (is_landmark_editable)  	{ -		mPlaceInfo->setLandmarkFolder(mItem->getParentUUID()); +		if(!mPlaceInfo->setLandmarkFolder(mItem->getParentUUID()) && !mItem->getParentUUID().isNull()) +		{ +			const LLViewerInventoryCategory* cat = gInventory.getCategory(mItem->getParentUUID()); +			if(cat) +			{ +				std::string cat_fullname = LLPanelPlaceInfo::getFullFolderName(cat); +				LLComboBox* folderList = mPlaceInfo->getChild<LLComboBox>("folder_combo"); +				folderList->add(cat_fullname, cat->getUUID(),ADD_TOP); +			} +		}  	}  	mPlaceInfo->displayItemInfo(mItem); diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp new file mode 100644 index 0000000000..ca7ebb1ad8 --- /dev/null +++ b/indra/newview/llpanelprimmediacontrols.cpp @@ -0,0 +1,1095 @@ +/**  + * @file llpanelprimmediacontrols.cpp + * @brief media controls popup panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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" + +//LLPanelPrimMediaControls +#include "llagent.h" +#include "llparcel.h" +#include "llpanel.h" +#include "llselectmgr.h" +#include "llmediaentry.h" +#include "llrender.h" +#include "lldrawable.h" +#include "llviewerwindow.h" +#include "lluictrlfactory.h" +#include "llbutton.h" +#include "llface.h" +#include "llcombobox.h" +#include "llslider.h" +#include "llhudview.h" +#include "lliconctrl.h" +#include "lltoolpie.h" +#include "llviewercamera.h" +#include "llviewerobjectlist.h" +#include "llpanelprimmediacontrols.h" +#include "llpluginclassmedia.h" +#include "llprogressbar.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" +#include "llvovolume.h" +#include "llweb.h" +#include "llwindow.h" + +glh::matrix4f glh_get_current_modelview(); +glh::matrix4f glh_get_current_projection(); + +const F32 ZOOM_NEAR_PADDING		= 1.0f; +const F32 ZOOM_MEDIUM_PADDING	= 1.15f; +const F32 ZOOM_FAR_PADDING		= 1.5f; + +// Warning: make sure these two match! +const LLPanelPrimMediaControls::EZoomLevel LLPanelPrimMediaControls::kZoomLevels[] = { ZOOM_NONE, ZOOM_MEDIUM }; +const int LLPanelPrimMediaControls::kNumZoomLevels = 2; + +// +// LLPanelPrimMediaControls +// + +LLPanelPrimMediaControls::LLPanelPrimMediaControls() :  +	mAlpha(1.f), +	mCurrentURL(""), +	mPreviousURL(""), +	mPauseFadeout(false), +	mUpdateSlider(true), +	mClearFaceOnFade(false), +	mCurrentRate(0.0), +	mMovieDuration(0.0), +	mUpdatePercent(0) +{ +	mCommitCallbackRegistrar.add("MediaCtrl.Close",		boost::bind(&LLPanelPrimMediaControls::onClickClose, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Back",		boost::bind(&LLPanelPrimMediaControls::onClickBack, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Forward",	boost::bind(&LLPanelPrimMediaControls::onClickForward, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Home",		boost::bind(&LLPanelPrimMediaControls::onClickHome, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Stop",		boost::bind(&LLPanelPrimMediaControls::onClickStop, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Reload",	boost::bind(&LLPanelPrimMediaControls::onClickReload, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Play",		boost::bind(&LLPanelPrimMediaControls::onClickPlay, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Pause",		boost::bind(&LLPanelPrimMediaControls::onClickPause, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Open",		boost::bind(&LLPanelPrimMediaControls::onClickOpen, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.Zoom",		boost::bind(&LLPanelPrimMediaControls::onClickZoom, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitURL",	boost::bind(&LLPanelPrimMediaControls::onCommitURL, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.JumpProgress",		boost::bind(&LLPanelPrimMediaControls::onCommitSlider, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeUp",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeUp, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.CommitVolumeDown",	boost::bind(&LLPanelPrimMediaControls::onCommitVolumeDown, this)); +	mCommitCallbackRegistrar.add("MediaCtrl.ToggleMute",		boost::bind(&LLPanelPrimMediaControls::onToggleMute, this)); +	 +	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_prim_media_controls.xml"); +	mInactivityTimer.reset(); +	mFadeTimer.stop(); +	mCurrentZoom = ZOOM_NONE; +	mScrollState = SCROLL_NONE; + +	mPanelHandle.bind(this); +} +LLPanelPrimMediaControls::~LLPanelPrimMediaControls() +{ +} + +BOOL LLPanelPrimMediaControls::postBuild() +{ +	LLButton* scroll_up_ctrl = getChild<LLButton>("scrollup"); +	scroll_up_ctrl->setClickedCallback(onScrollUp, this); +	scroll_up_ctrl->setHeldDownCallback(onScrollUpHeld, this); +	scroll_up_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_left_ctrl = getChild<LLButton>("scrollleft"); +	scroll_left_ctrl->setClickedCallback(onScrollLeft, this); +	scroll_left_ctrl->setHeldDownCallback(onScrollLeftHeld, this); +	scroll_left_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_right_ctrl = getChild<LLButton>("scrollright"); +	scroll_right_ctrl->setClickedCallback(onScrollRight, this); +	scroll_right_ctrl->setHeldDownCallback(onScrollLeftHeld, this); +	scroll_right_ctrl->setMouseUpCallback(onScrollStop, this); +	LLButton* scroll_down_ctrl = getChild<LLButton>("scrolldown"); +	scroll_down_ctrl->setClickedCallback(onScrollDown, this); +	scroll_down_ctrl->setHeldDownCallback(onScrollDownHeld, this); +	scroll_down_ctrl->setMouseUpCallback(onScrollStop, this); +	 +	LLUICtrl* media_address	= getChild<LLUICtrl>("media_address"); +	media_address->setFocusReceivedCallback(boost::bind(&LLPanelPrimMediaControls::onInputURL, _1, this )); +	mInactiveTimeout = gSavedSettings.getF32("MediaControlTimeout"); +	mControlFadeTime = gSavedSettings.getF32("MediaControlFadeTime"); + +	mCurrentZoom = ZOOM_NONE; +	// clicks on HUD buttons do not remove keyboard focus from media +	setIsChrome(TRUE); +	return TRUE; +} + +void LLPanelPrimMediaControls::setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal) +{ +	if (media_impl.notNull() && objectp.notNull()) +	{ +		mTargetImplID = media_impl->getMediaTextureID(); +		mTargetObjectID = objectp->getID(); +		mTargetObjectFace = face; +		mTargetObjectNormal = pick_normal; +		mClearFaceOnFade = false; +	} +	else +	{ +		// This happens on a timer now. +//		mTargetImplID = LLUUID::null; +//		mTargetObjectID = LLUUID::null; +//		mTargetObjectFace = 0; +		mClearFaceOnFade = true; +	} + +	updateShape(); +} + +void LLPanelPrimMediaControls::focusOnTarget() +{ +	// Sets the media focus to the current target of the LLPanelPrimMediaControls. +	// This is how we transition from hover to focus when the user clicks on a control. +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if(media_impl) +	{ +		if(!media_impl->hasFocus()) +		{	 +			// The current target doesn't have media focus -- focus on it. +			LLViewerObject* objectp = getTargetObject(); +			LLViewerMediaFocus::getInstance()->setFocusFace(objectp, mTargetObjectFace, media_impl, mTargetObjectNormal); +		} +	}	 +} + +LLViewerMediaImpl* LLPanelPrimMediaControls::getTargetMediaImpl() +{ +	return LLViewerMedia::getMediaImplFromTextureID(mTargetImplID); +} + +LLViewerObject* LLPanelPrimMediaControls::getTargetObject() +{ +	return gObjectList.findObject(mTargetObjectID); +} + +LLPluginClassMedia* LLPanelPrimMediaControls::getTargetMediaPlugin() +{ +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	if(impl && impl->hasMedia()) +	{ +		return impl->getMediaPlugin(); +	} +	 +	return NULL; +} + +void LLPanelPrimMediaControls::updateShape() +{ +	const S32 MIN_HUD_WIDTH=400; +	const S32 MIN_HUD_HEIGHT=120; + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	LLViewerObject* objectp = getTargetObject(); +	 +	if(!media_impl) +	{ +		setVisible(FALSE); +		return; +	} + +	LLPluginClassMedia* media_plugin = NULL; +	if(media_impl->hasMedia()) +	{ +		media_plugin = media_impl->getMediaPlugin(); +	} +	 +	LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + +	bool can_navigate = parcel->getMediaAllowNavigate(); +	bool enabled = false; +	bool has_focus = media_impl->hasFocus(); +	setVisible(enabled); + +	if (objectp) +	{ +		bool mini_controls = false; +		LLMediaEntry *media_data = objectp->getTE(mTargetObjectFace)->getMediaData(); +		if (media_data && NULL != dynamic_cast<LLVOVolume*>(objectp)) +		{ +			// Don't show the media HUD if we do not have permissions +			enabled = dynamic_cast<LLVOVolume*>(objectp)->hasMediaPermission(media_data, LLVOVolume::MEDIA_PERM_CONTROL); +			mini_controls = (LLMediaEntry::MINI == media_data->getControls()); +		} +		 +		// +		// Set the state of the buttons +		// +		LLUICtrl* back_ctrl					= getChild<LLUICtrl>("back"); +		LLUICtrl* fwd_ctrl					= getChild<LLUICtrl>("fwd"); +		LLUICtrl* reload_ctrl				= getChild<LLUICtrl>("reload"); +		LLUICtrl* play_ctrl					= getChild<LLUICtrl>("play"); +		LLUICtrl* pause_ctrl				= getChild<LLUICtrl>("pause"); +		LLUICtrl* stop_ctrl					= getChild<LLUICtrl>("stop"); +		LLUICtrl* media_stop_ctrl			= getChild<LLUICtrl>("media_stop"); +		LLUICtrl* home_ctrl					= getChild<LLUICtrl>("home"); +		LLUICtrl* close_ctrl				= getChild<LLUICtrl>("close"); +		LLUICtrl* open_ctrl					= getChild<LLUICtrl>("new_window"); +        LLUICtrl* zoom_ctrl					= getChild<LLUICtrl>("zoom_frame"); +		LLPanel* media_loading_panel		= getChild<LLPanel>("media_progress_indicator"); +		LLUICtrl* media_address_ctrl		= getChild<LLUICtrl>("media_address"); +		LLUICtrl* media_play_slider_ctrl	= getChild<LLUICtrl>("media_play_position"); +		LLUICtrl* volume_ctrl				= getChild<LLUICtrl>("media_volume"); +		LLButton* volume_btn				= getChild<LLButton>("media_volume_button"); +		LLUICtrl* volume_up_ctrl			= getChild<LLUICtrl>("volume_up"); +		LLUICtrl* volume_down_ctrl			= getChild<LLUICtrl>("volume_down"); +		LLIconCtrl* whitelist_icon			= getChild<LLIconCtrl>("media_whitelist_flag"); +		LLIconCtrl* secure_lock_icon		= getChild<LLIconCtrl>("media_secure_lock_flag"); +		 +		LLUICtrl* media_panel_scroll		= getChild<LLUICtrl>("media_panel_scroll"); +		LLUICtrl* scroll_up_ctrl			= getChild<LLUICtrl>("scrollup"); +		LLUICtrl* scroll_left_ctrl			= getChild<LLUICtrl>("scrollleft"); +		LLUICtrl* scroll_right_ctrl			= getChild<LLUICtrl>("scrollright"); +		LLUICtrl* scroll_down_ctrl			= getChild<LLUICtrl>("scrolldown");		 +				 +		// XXX RSP: TODO: FIXME: clean this up so that it is clearer what mode we are in, +		// and that only the proper controls get made visible/enabled according to that mode.  +		back_ctrl->setVisible(has_focus); +		fwd_ctrl->setVisible(has_focus); +		reload_ctrl->setVisible(has_focus); +		stop_ctrl->setVisible(false); +		home_ctrl->setVisible(has_focus); +		close_ctrl->setVisible(has_focus); +		open_ctrl->setVisible(true); +		media_address_ctrl->setVisible(has_focus && !mini_controls); +		media_play_slider_ctrl->setVisible(has_focus && !mini_controls); +		volume_ctrl->setVisible(false); +		volume_up_ctrl->setVisible(false); +		volume_down_ctrl->setVisible(false); +		 +		whitelist_icon->setVisible(!mini_controls && (media_data)?media_data->getWhiteListEnable():false); +		// Disable zoom if HUD +		zoom_ctrl->setEnabled(!objectp->isHUDAttachment()); +		secure_lock_icon->setVisible(false); +		mCurrentURL = media_impl->getMediaURL(); +		 +		back_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateBack() && can_navigate); +		fwd_ctrl->setEnabled((media_impl != NULL) && media_impl->canNavigateForward() && can_navigate); +		stop_ctrl->setEnabled(has_focus && can_navigate); +		home_ctrl->setEnabled(has_focus && can_navigate); +		LLPluginClassMediaOwner::EMediaStatus result = ((media_impl != NULL) && media_impl->hasMedia()) ? media_plugin->getStatus() : LLPluginClassMediaOwner::MEDIA_NONE; + +		if(media_plugin && media_plugin->pluginSupportsMediaTime()) +		{ +			reload_ctrl->setEnabled(FALSE); +			reload_ctrl->setVisible(FALSE); +			media_stop_ctrl->setVisible(has_focus); +			home_ctrl->setVisible(FALSE); +			back_ctrl->setEnabled(has_focus); +			fwd_ctrl->setEnabled(has_focus); +			media_address_ctrl->setVisible(false); +			media_address_ctrl->setEnabled(false); +			media_play_slider_ctrl->setVisible(!mini_controls); +			media_play_slider_ctrl->setEnabled(!mini_controls); +				 +			volume_ctrl->setVisible(has_focus); +			volume_up_ctrl->setVisible(has_focus); +			volume_down_ctrl->setVisible(has_focus); +			volume_ctrl->setEnabled(has_focus); + +			whitelist_icon->setVisible(false); +			secure_lock_icon->setVisible(false); +			scroll_up_ctrl->setVisible(false); +			scroll_left_ctrl->setVisible(false); +			scroll_right_ctrl->setVisible(false); +			scroll_down_ctrl->setVisible(false); +			media_panel_scroll->setVisible(false); +				 +			F32 volume = media_impl->getVolume(); +			// movie's url changed +			if(mCurrentURL!=mPreviousURL) +			{ +				mMovieDuration = media_plugin->getDuration(); +				mPreviousURL = mCurrentURL; +			} +				 +			if(mMovieDuration == 0)  +			{ +				mMovieDuration = media_plugin->getDuration(); +				media_play_slider_ctrl->setValue(0); +				media_play_slider_ctrl->setEnabled(false); +			} +			// TODO: What if it's not fully loaded +					 +			if(mUpdateSlider && mMovieDuration!= 0) +			{ +				F64 current_time =  media_plugin->getCurrentTime(); +				F32 percent = current_time / mMovieDuration; +				media_play_slider_ctrl->setValue(percent); +				media_play_slider_ctrl->setEnabled(true); +			} +				 +			// video vloume +			if(volume <= 0.0) +			{ +				volume_up_ctrl->setEnabled(TRUE); +				volume_down_ctrl->setEnabled(FALSE); +				media_impl->setVolume(0.0); +				volume_btn->setToggleState(true); +			} +			else if (volume >= 1.0) +			{ +				volume_up_ctrl->setEnabled(FALSE); +				volume_down_ctrl->setEnabled(TRUE); +				media_impl->setVolume(1.0); +				volume_btn->setToggleState(false); +			} +			else +			{ +				volume_up_ctrl->setEnabled(TRUE); +				volume_down_ctrl->setEnabled(TRUE); +			} +				 +			switch(result) +			{ +				case LLPluginClassMediaOwner::MEDIA_PLAYING: +					play_ctrl->setEnabled(FALSE); +					play_ctrl->setVisible(FALSE); +					pause_ctrl->setEnabled(TRUE); +					pause_ctrl->setVisible(has_focus); +					media_stop_ctrl->setEnabled(TRUE); +					 +					break; +				case LLPluginClassMediaOwner::MEDIA_PAUSED: +				default: +					pause_ctrl->setEnabled(FALSE); +					pause_ctrl->setVisible(FALSE); +					play_ctrl->setEnabled(TRUE); +					play_ctrl->setVisible(has_focus); +					media_stop_ctrl->setEnabled(FALSE); +					break; +			} +		} +		else   // web based +		{ +			if(media_plugin) +			{ +				mCurrentURL = media_plugin->getLocation(); +			} +			else +			{ +				mCurrentURL.clear(); +			} +				 +			play_ctrl->setVisible(FALSE); +			pause_ctrl->setVisible(FALSE); +			media_stop_ctrl->setVisible(FALSE); +			media_address_ctrl->setVisible(has_focus && !mini_controls); +			media_address_ctrl->setEnabled(has_focus && !mini_controls); +			media_play_slider_ctrl->setVisible(FALSE); +			media_play_slider_ctrl->setEnabled(FALSE); +				 +			volume_ctrl->setVisible(FALSE); +			volume_up_ctrl->setVisible(FALSE); +			volume_down_ctrl->setVisible(FALSE); +			volume_ctrl->setEnabled(FALSE); +			volume_up_ctrl->setEnabled(FALSE); +			volume_down_ctrl->setEnabled(FALSE); +				 +			scroll_up_ctrl->setVisible(has_focus); +			scroll_left_ctrl->setVisible(has_focus); +			scroll_right_ctrl->setVisible(has_focus); +			scroll_down_ctrl->setVisible(has_focus); +			media_panel_scroll->setVisible(has_focus); +			// TODO: get the secure lock bool from media plug in +			std::string prefix =  std::string("https://"); +			std::string test_prefix = mCurrentURL.substr(0, prefix.length()); +			LLStringUtil::toLower(test_prefix); +			if(test_prefix == prefix) +			{ +				secure_lock_icon->setVisible(has_focus); +			} +				 +			if(mCurrentURL!=mPreviousURL) +			{ +				setCurrentURL(); +				mPreviousURL = mCurrentURL; +			} + +			if(result == LLPluginClassMediaOwner::MEDIA_LOADING) +			{ +				reload_ctrl->setEnabled(FALSE); +				reload_ctrl->setVisible(FALSE); +				stop_ctrl->setEnabled(TRUE); +				stop_ctrl->setVisible(has_focus); +			} +			else +			{ +				reload_ctrl->setEnabled(TRUE); +				reload_ctrl->setVisible(has_focus); +				stop_ctrl->setEnabled(FALSE); +				stop_ctrl->setVisible(FALSE); +			} +		} + +		 +		if(media_plugin) +		{ +			// +			// Handle progress bar +			// +			mUpdatePercent = media_plugin->getProgressPercent(); +			if(mUpdatePercent<100.0f) +			{ +				media_loading_panel->setVisible(true); +				getChild<LLProgressBar>("media_progress_bar")->setPercent(mUpdatePercent); +				gFocusMgr.setTopCtrl(media_loading_panel); +			} +			else +			{ +				media_loading_panel->setVisible(false); +				gFocusMgr.setTopCtrl(NULL); +			} +		} + +		if(media_plugin) +		{ +			// +			// Handle Scrolling +			// +			switch (mScrollState)  +			{ +			case SCROLL_UP: +				media_plugin->scrollEvent(0, -1, MASK_NONE); +				break; +			case SCROLL_DOWN: +				media_plugin->scrollEvent(0, 1, MASK_NONE); +				break; +			case SCROLL_LEFT: +				media_impl->handleKeyHere(KEY_LEFT, MASK_NONE); +				break; +			case SCROLL_RIGHT: +				media_impl->handleKeyHere(KEY_RIGHT, MASK_NONE); +				break; +			case SCROLL_NONE: +			default: +				break; +			} +		} +		 +		setVisible(enabled); + +		// +		// Calculate position and shape of the controls +		// +		glh::matrix4f mat = glh_get_current_projection()*glh_get_current_modelview(); +		std::vector<LLVector3>::iterator vert_it; +		std::vector<LLVector3>::iterator vert_end; +		std::vector<LLVector3> vect_face; + +		LLVolume* volume = objectp->getVolume(); + +		if (volume) +		{ +			const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace); + +			const LLVector3* ext = vf.mExtents; + +			LLVector3 center = (ext[0]+ext[1])*0.5f; +			LLVector3 size = (ext[1]-ext[0])*0.5f; +			LLVector3 vert[] = +			{ +				center + size.scaledVec(LLVector3(1,1,1)), +				center + size.scaledVec(LLVector3(-1,1,1)), +				center + size.scaledVec(LLVector3(1,-1,1)), +				center + size.scaledVec(LLVector3(-1,-1,1)), +				center + size.scaledVec(LLVector3(1,1,-1)), +				center + size.scaledVec(LLVector3(-1,1,-1)), +				center + size.scaledVec(LLVector3(1,-1,-1)), +				center + size.scaledVec(LLVector3(-1,-1,-1)), +			}; + +			LLVOVolume* vo = (LLVOVolume*) objectp; + +			for (U32 i = 0; i < 8; i++) +			{ +				vect_face.push_back(vo->volumePositionToAgent(vert[i]));	 +			} +		} +		vert_it = vect_face.begin(); +		vert_end = vect_face.end(); + +		LLVector3 min = LLVector3(1,1,1); +		LLVector3 max = LLVector3(-1,-1,-1); +		for(; vert_it != vert_end; ++vert_it) +		{ +			// project silhouette vertices into screen space +			glh::vec3f screen_vert = glh::vec3f(vert_it->mV);  +			mat.mult_matrix_vec(screen_vert); + +			// add to screenspace bounding box +			update_min_max(min, max, LLVector3(screen_vert.v)); +		} + +        LLCoordGL screen_min; +		screen_min.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (min.mV[VX] + 1.f) * 0.5f); +		screen_min.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (min.mV[VY] + 1.f) * 0.5f); + +		LLCoordGL screen_max; +		screen_max.mX = llround((F32)gViewerWindow->getWorldViewWidth() * (max.mV[VX] + 1.f) * 0.5f); +		screen_max.mY = llround((F32)gViewerWindow->getWorldViewHeight() * (max.mV[VY] + 1.f) * 0.5f); + +		// grow panel so that screenspace bounding box fits inside "media_region" element of HUD +		LLRect media_controls_rect; +		getParent()->screenRectToLocal(LLRect(screen_min.mX, screen_max.mY, screen_max.mX, screen_min.mY), &media_controls_rect); +		LLView* media_region = getChild<LLView>("media_region"); +		media_controls_rect.mLeft -= media_region->getRect().mLeft; +		media_controls_rect.mBottom -= media_region->getRect().mBottom; +		media_controls_rect.mTop += getRect().getHeight() - media_region->getRect().mTop; +		media_controls_rect.mRight += getRect().getWidth() - media_region->getRect().mRight; + +		LLRect old_hud_rect = media_controls_rect; +		// keep all parts of HUD on-screen +		media_controls_rect.intersectWith(getParent()->getLocalRect()); + +		// clamp to minimum size, keeping centered +		media_controls_rect.setCenterAndSize(media_controls_rect.getCenterX(), media_controls_rect.getCenterY(), +			llmax(MIN_HUD_WIDTH, media_controls_rect.getWidth()), llmax(MIN_HUD_HEIGHT, media_controls_rect.getHeight())); + +		setShape(media_controls_rect, true); + +		// Test mouse position to see if the cursor is stationary +		LLCoordWindow cursor_pos_window; +		getWindow()->getCursorPosition(&cursor_pos_window); + +		// If last pos is not equal to current pos, the mouse has moved +		// We need to reset the timer, and make sure the panel is visible +		if(cursor_pos_window.mX != mLastCursorPos.mX || +			cursor_pos_window.mY != mLastCursorPos.mY || +			mScrollState != SCROLL_NONE) +		{ +			mInactivityTimer.start(); +			mLastCursorPos = cursor_pos_window; +		} +		 +		if(isMouseOver()) +		{ +			// Never fade the controls if the mouse is over them. +			mFadeTimer.stop(); +		} +		else if(!mClearFaceOnFade && (mInactivityTimer.getElapsedTimeF32() < mInactiveTimeout)) +		{ +			// Mouse is over the object, but has not been stationary for long enough to fade the UI +			mFadeTimer.stop(); +		} +		else if(! mFadeTimer.getStarted() ) +		{ +			// we need to start fading the UI (and we have not already started) +			mFadeTimer.reset(); +			mFadeTimer.start(); +		} +		else +		{ +			// I don't think this is correct anymore.  This is done in draw() after the fade has completed. +//			setVisible(FALSE); +		} +	} +} + +/*virtual*/ +void LLPanelPrimMediaControls::draw() +{ +	F32 alpha = 1.f; +	if(mFadeTimer.getStarted()) +	{ +		F32 time = mFadeTimer.getElapsedTimeF32(); +		alpha = llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f); + +		if(mFadeTimer.getElapsedTimeF32() >= mControlFadeTime) +		{ +			setVisible(FALSE); +			if(mClearFaceOnFade) +			{ +				mClearFaceOnFade = false; +				mTargetImplID = LLUUID::null; +				mTargetObjectID = LLUUID::null; +				mTargetObjectFace = 0; +			} +		} +	} +	 +	{ +		LLViewDrawContext context(alpha); +		LLPanel::draw(); +	} +} + +BOOL LLPanelPrimMediaControls::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ +	mInactivityTimer.start(); +	return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} + +BOOL LLPanelPrimMediaControls::handleMouseDown(S32 x, S32 y, MASK mask) +{ +	mInactivityTimer.start(); +	return LLPanel::handleMouseDown(x, y, mask); +} + +BOOL LLPanelPrimMediaControls::handleMouseUp(S32 x, S32 y, MASK mask) +{ +	mInactivityTimer.start(); +	return LLPanel::handleMouseUp(x, y, mask); +} + +BOOL LLPanelPrimMediaControls::handleKeyHere( KEY key, MASK mask ) +{ +	mInactivityTimer.start(); +	return LLPanel::handleKeyHere(key, mask); +} + +bool LLPanelPrimMediaControls::isMouseOver() +{ +	bool result = false; +	 +	if( getVisible() ) +	{ +		LLCoordWindow cursor_pos_window; +		LLCoordScreen cursor_pos_screen; +		LLCoordGL cursor_pos_gl; +		S32 x, y; +		getWindow()->getCursorPosition(&cursor_pos_window); +		getWindow()->convertCoords(cursor_pos_window, &cursor_pos_gl); +		 +		LLPanel* controls_panel = NULL; +		controls_panel = getChild<LLPanel>("media_hover_controls"); +		if(controls_panel && !controls_panel->getVisible()) +		{ +			// The hover controls aren't visible -- use the focused controls instead. +			controls_panel = getChild<LLPanel>("media_focused_controls"); +		} +		 +		if(controls_panel && controls_panel->getVisible()) +		{ +			controls_panel->screenPointToLocal(cursor_pos_gl.mX, cursor_pos_gl.mY, &x, &y); + +			LLView *hit_child = controls_panel->childFromPoint(x, y); +			if(hit_child) +			{ +				// This was useful for debugging both coordinate translation and view hieararchy problems... +//				llinfos << "mouse coords: " << x << ", " << y << " hit child " << hit_child->getName() << llendl; +				result = true; +			} +		} +	} + +	return result; +} + + +void LLPanelPrimMediaControls::onClickClose() +{ +	close(); +} + +void LLPanelPrimMediaControls::close() +{ +	LLViewerMediaFocus::getInstance()->clearFocus(); +	resetZoomLevel(); +	setVisible(FALSE); +} + + +void LLPanelPrimMediaControls::onClickBack() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl =getTargetMediaImpl(); +	 +	if (impl) +	{ +		impl->navigateBack(); +	} +} + +void LLPanelPrimMediaControls::onClickForward() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); +	 +	if (impl) +	{ +		impl->navigateForward(); +	} +} + +void LLPanelPrimMediaControls::onClickHome() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->navigateHome(); +	} +} + +void LLPanelPrimMediaControls::onClickOpen() +{ +	LLViewerMediaImpl* impl =getTargetMediaImpl(); +	if(impl) +	{ +		if(impl->getMediaPlugin()) +		{	 +			if(impl->getMediaPlugin()->getLocation().empty()) +			{ +				LLWeb::loadURL(impl->getMediaURL()); +			} +			else +			{ +				LLWeb::loadURL( impl->getMediaPlugin()->getLocation()); +			} +		} +	}	 +} + +void LLPanelPrimMediaControls::onClickReload() +{ +	focusOnTarget(); + +	//LLViewerMedia::navigateHome(); +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->navigateReload(); +	} +} + +void LLPanelPrimMediaControls::onClickPlay() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->play(); +	} +} + +void LLPanelPrimMediaControls::onClickPause() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->pause(); +	} +} + +void LLPanelPrimMediaControls::onClickStop() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* impl = getTargetMediaImpl(); + +	if(impl) +	{ +		impl->stop(); +	} +} + +void LLPanelPrimMediaControls::onClickZoom() +{ +	focusOnTarget(); + +	nextZoomLevel(); +} +void LLPanelPrimMediaControls::nextZoomLevel() +{ +	int index = 0; +	while (index < kNumZoomLevels) +	{ +		if (kZoomLevels[index] == mCurrentZoom)  +		{ +			index++; +			break; +		} +		index++; +	} +	mCurrentZoom = kZoomLevels[index % kNumZoomLevels]; +	updateZoom(); +} + +void LLPanelPrimMediaControls::resetZoomLevel() +{ +	if(mCurrentZoom != ZOOM_NONE) +	{ +		mCurrentZoom = ZOOM_NONE; +		updateZoom(); +	} +} + +void LLPanelPrimMediaControls::updateZoom() +{ +	F32 zoom_padding = 0.0f; +	switch (mCurrentZoom) +	{ +	case ZOOM_NONE: +		{ +			gAgent.setFocusOnAvatar(TRUE, ANIMATE); +			break; +		} +	case ZOOM_FAR: +		{ +			zoom_padding = ZOOM_FAR_PADDING; +			break; +		} +	case ZOOM_MEDIUM: +		{ +			zoom_padding = ZOOM_MEDIUM_PADDING; +			break; +		} +	case ZOOM_NEAR: +		{ +			zoom_padding = ZOOM_NEAR_PADDING; +			break; +		} +	default: +		{ +			gAgent.setFocusOnAvatar(TRUE, ANIMATE); +			break; +		} +	} + +	if (zoom_padding > 0.0f)		 +		LLViewerMediaFocus::setCameraZoom(getTargetObject(), mTargetObjectNormal, zoom_padding); +} +void LLPanelPrimMediaControls::onScrollUp(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin(); +	 +	if(plugin) +	{ +		plugin->scrollEvent(0, -1, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollUpHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_UP; +} +void LLPanelPrimMediaControls::onScrollRight(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl(); + +	if(impl) +	{ +		impl->handleKeyHere(KEY_RIGHT, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollRightHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_RIGHT; +} + +void LLPanelPrimMediaControls::onScrollLeft(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLViewerMediaImpl* impl = this_panel->getTargetMediaImpl(); + +	if(impl) +	{ +		impl->handleKeyHere(KEY_LEFT, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollLeftHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_LEFT; +} + +void LLPanelPrimMediaControls::onScrollDown(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->focusOnTarget(); + +	LLPluginClassMedia* plugin = this_panel->getTargetMediaPlugin(); +	 +	if(plugin) +	{ +		plugin->scrollEvent(0, 1, MASK_NONE); +	} +} +void LLPanelPrimMediaControls::onScrollDownHeld(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_DOWN; +} + +void LLPanelPrimMediaControls::onScrollStop(void* user_data) +{ +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (user_data); +	this_panel->mScrollState = SCROLL_NONE; +} + +void LLPanelPrimMediaControls::onCommitURL() +{ +	focusOnTarget(); + +	LLUICtrl *media_address_ctrl = getChild<LLUICtrl>("media_address_url"); +	std::string url = media_address_ctrl->getValue().asString(); +	if(getTargetMediaImpl() && !url.empty()) +	{ +		getTargetMediaImpl()->navigateTo( url, "", true); + +		// Make sure keyboard focus is set to the media focus object. +		gFocusMgr.setKeyboardFocus(LLViewerMediaFocus::getInstance()); +			 +	} +	mPauseFadeout = false; +	mFadeTimer.start(); +} + + +void LLPanelPrimMediaControls::onInputURL(LLFocusableElement* caller, void *userdata) +{ + +	LLPanelPrimMediaControls* this_panel = static_cast<LLPanelPrimMediaControls*> (userdata); +	this_panel->focusOnTarget(); + +	this_panel->mPauseFadeout = true; +	this_panel->mFadeTimer.stop(); +	this_panel->mFadeTimer.reset(); +	 +} + +void LLPanelPrimMediaControls::setCurrentURL() +{	 +	LLComboBox* media_address_combo	= getChild<LLComboBox>("media_address_combo"); +	// redirects will navigate momentarily to about:blank, don't add to history +	if (media_address_combo && mCurrentURL != "about:blank") +	{ +		media_address_combo->remove(mCurrentURL); +		media_address_combo->add(mCurrentURL, ADD_SORTED); +		media_address_combo->selectByValue(mCurrentURL); +	} +} + +void LLPanelPrimMediaControls::onCommitSlider() +{ +	focusOnTarget(); + +	LLSlider* media_play_slider_ctrl	= getChild<LLSlider>("media_play_slider"); +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		// get slider value +		F64 slider_value = media_play_slider_ctrl->getValue().asReal(); +		if(slider_value <= 0.0) +		{	 +			media_impl->stop(); +		} +		else  +		{ +			media_impl->seek(slider_value*mMovieDuration); +			//mUpdateSlider= false; +		} +	} +}		 + +void LLPanelPrimMediaControls::onCommitVolumeUp() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		volume += 0.1f; +		if(volume >= 1.0f) +		{ +			volume = 1.0f; +		} +		 +		media_impl->setVolume(volume); +		getChild<LLButton>("media_volume")->setToggleState(false); +	} +}		 + +void LLPanelPrimMediaControls::onCommitVolumeDown() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		volume -= 0.1f; +		if(volume <= 0.0f) +		{ +			volume = 0.0f; +		} + +		media_impl->setVolume(volume); +		getChild<LLButton>("media_volume")->setToggleState(false); +	} +}		 + + +void LLPanelPrimMediaControls::onToggleMute() +{ +	focusOnTarget(); + +	LLViewerMediaImpl* media_impl = getTargetMediaImpl(); +	if (media_impl)  +	{ +		F32 volume = media_impl->getVolume(); +		 +		if(volume > 0.0) +		{ +			media_impl->setVolume(0.0); +		} +		else  +		{ +			media_impl->setVolume(0.5); +		} +	} +} + diff --git a/indra/newview/llpanelprimmediacontrols.h b/indra/newview/llpanelprimmediacontrols.h new file mode 100644 index 0000000000..3ec7aa2356 --- /dev/null +++ b/indra/newview/llpanelprimmediacontrols.h @@ -0,0 +1,148 @@ +/**  + * @file llpanelprimmediacontrols.h + * @brief Pop-up media controls panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + *  + * Copyright (c) 2003-2007, 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://secondlife.com/developers/opensource/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://secondlife.com/developers/opensource/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$ + */ + +#ifndef LL_PANELPRIMMEDIACONTROLS_H +#define LL_PANELPRIMMEDIACONTROLS_H + +#include "llpanel.h" +#include "llviewermedia.h" + +class LLCoordWindow; +class LLViewerMediaImpl; + +class LLPanelPrimMediaControls : public LLPanel +{ +public: +	LLPanelPrimMediaControls(); +	virtual ~LLPanelPrimMediaControls(); +	/*virtual*/ BOOL postBuild(); +	virtual void draw(); +	virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + +	virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); +	virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); +	virtual BOOL handleKeyHere(KEY key, MASK mask); +	 +	void updateShape(); +	bool isMouseOver(); +	void nextZoomLevel(); +	void resetZoomLevel(); +	void close(); + +	LLHandle<LLPanelPrimMediaControls>	getHandle() const { return mPanelHandle; } +	void setMediaFace(LLPointer<LLViewerObject> objectp, S32 face, viewer_media_t media_impl, LLVector3 pick_normal = LLVector3::zero); + + +	enum EZoomLevel +	{ +		ZOOM_NONE = 0, +		ZOOM_FAR, +		ZOOM_MEDIUM, +		ZOOM_NEAR +	}; +	static const EZoomLevel kZoomLevels[]; +	static const int kNumZoomLevels; +	 +	enum EScrollDir +	{ +		SCROLL_UP = 0, +		SCROLL_DOWN, +		SCROLL_LEFT, +		SCROLL_RIGHT, +		SCROLL_NONE +	}; + +private: +	void onClickClose(); +	void onClickBack(); +	void onClickForward(); +	void onClickHome(); +	void onClickOpen(); +	void onClickReload(); +	void onClickPlay(); +	void onClickPause(); +	void onClickStop(); +	void onClickZoom(); +	void onCommitURL(); +	 +	void updateZoom(); +	void setCurrentURL(); +	void onCommitSlider(); +	 +	void onCommitVolumeUp(); +	void onCommitVolumeDown(); +	void onToggleMute(); +	 +	static void onScrollUp(void* user_data); +	static void onScrollUpHeld(void* user_data); +	static void onScrollLeft(void* user_data); +	static void onScrollLeftHeld(void* user_data); +	static void onScrollRight(void* user_data); +	static void onScrollRightHeld(void* user_data); +	static void onScrollDown(void* user_data); +	static void onScrollDownHeld(void* user_data); +	static void onScrollStop(void* user_data); +	 +	static void onInputURL(LLFocusableElement* caller, void *userdata); +	static bool hasControlsPermission(LLViewerObject *obj, const LLMediaEntry *media_entry); +	 +	void focusOnTarget(); +	 +	LLViewerMediaImpl* getTargetMediaImpl(); +	LLViewerObject* getTargetObject(); +	LLPluginClassMedia* getTargetMediaPlugin(); +	bool mPauseFadeout; +	bool mUpdateSlider; +	bool mClearFaceOnFade; + +	LLMatrix4 mLastCameraMat; +	EZoomLevel mCurrentZoom; +	EScrollDir mScrollState; +	LLCoordWindow mLastCursorPos; +	LLFrameTimer mInactivityTimer; +	LLFrameTimer mFadeTimer; +	F32 mInactiveTimeout; +	F32 mControlFadeTime; +	LLRootHandle<LLPanelPrimMediaControls> mPanelHandle; +	F32 mAlpha; +	std::string mCurrentURL; +	std::string mPreviousURL; +	F64 mCurrentRate; +	F64 mMovieDuration; +	int mUpdatePercent; + +	LLUUID mTargetObjectID; +	S32 mTargetObjectFace; +	LLUUID mTargetImplID; +	LLVector3 mTargetObjectNormal; +}; + +#endif // LL_PANELPRIMMEDIACONTROLS_H diff --git a/indra/newview/llparticipantlist.cpp b/indra/newview/llparticipantlist.cpp index 25e773e8b8..e97eb1df2b 100644 --- a/indra/newview/llparticipantlist.cpp +++ b/indra/newview/llparticipantlist.cpp @@ -34,7 +34,7 @@  #include "llparticipantlist.h"  #include "llavatarlist.h" -#include "llfloateractivespeakers.h" +#include "llspeakers.h"  //LLParticipantList retrieves add, clear and remove events and updates view accordingly   LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* avatar_list): @@ -48,6 +48,18 @@ LLParticipantList::LLParticipantList(LLSpeakerMgr* data_source, LLAvatarList* av  	mSpeakerMgr->addListener(mSpeakerAddListener, "add");  	mSpeakerMgr->addListener(mSpeakerRemoveListener, "remove");  	mSpeakerMgr->addListener(mSpeakerClearListener, "clear"); + +	//Lets fill avatarList with existing speakers +	LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); + +	LLSpeakerMgr::speaker_list_t speaker_list; +	mSpeakerMgr->getSpeakerList(&speaker_list, true); +	for(LLSpeakerMgr::speaker_list_t::iterator it = speaker_list.begin(); it != speaker_list.end(); it++) +	{ +		group_members.push_back((*it)->mID); +	} +	mAvatarList->setDirty(); +	mAvatarList->sortByName();  }  LLParticipantList::~LLParticipantList() @@ -87,8 +99,12 @@ bool LLParticipantList::SpeakerAddListener::handleEvent(LLPointer<LLOldEvents::L  bool LLParticipantList::SpeakerRemoveListener::handleEvent(LLPointer<LLOldEvents::LLEvent> event, const LLSD& userdata)  {  	LLAvatarList::uuid_vector_t& group_members = mAvatarList->getIDs(); -	group_members.erase(std::find(group_members.begin(), group_members.end(), event->getValue().asUUID())); -	mAvatarList->setDirty(); +	LLAvatarList::uuid_vector_t::iterator pos = std::find(group_members.begin(), group_members.end(), event->getValue().asUUID()); +	if(pos != group_members.end()) +	{ +		group_members.erase(pos); +		mAvatarList->setDirty(); +	}  	return true;  } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 1683d113a9..73dcd1dd92 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -191,19 +191,22 @@ void LLScreenChannel::onToastFade(LLToast* toast)  {	  	std::vector<ToastElem>::iterator it = find(mToastList.begin(), mToastList.end(), static_cast<LLPanel*>(toast)); -	bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored(); -	if(delete_toast) -	{ -		mToastList.erase(it); -		deleteToast(toast); -	} -	else +	if(it != mToastList.end())  	{ -		storeToast((*it)); -		mToastList.erase(it); -	}	 +		bool delete_toast = !mCanStoreToasts || !toast->getCanBeStored(); +		if(delete_toast) +		{ +			mToastList.erase(it); +			deleteToast(toast); +		} +		else +		{ +			storeToast((*it)); +			mToastList.erase(it); +		}	 -	redrawToasts(); +		redrawToasts(); +	}  }  //-------------------------------------------------------------------------- @@ -247,6 +250,7 @@ void LLScreenChannel::loadStoredToastsToChannel()  	for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it)  	{ +		(*it).toast->setIsHidden(false);  		(*it).toast->resetTimer();  		mToastList.push_back((*it));  	} @@ -266,6 +270,7 @@ void LLScreenChannel::loadStoredToastByNotificationIDToChannel(LLUUID id)  	mOverflowToastHidden = false;  	LLToast* toast = (*it).toast; +	toast->setIsHidden(false);  	toast->resetTimer();  	mToastList.push_back((*it));  	mStoredToastList.erase(it); @@ -519,6 +524,7 @@ void LLScreenChannel::createStartUpToast(S32 notif_num, F32 timer)  	LLRect toast_rect;  	LLToast::Params p;  	p.lifetime_secs = timer; +	p.enable_hide_btn = false;  	mStartUpToastPanel = new LLToast(p);  	if(!mStartUpToastPanel) diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp new file mode 100644 index 0000000000..2341fcfc6d --- /dev/null +++ b/indra/newview/llspeakers.cpp @@ -0,0 +1,639 @@ +/**  + * @file llspeakers.cpp + * @brief Management interface for muting and controlling volume of residents currently speaking + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + *  + * Copyright (c) 2005-2009, 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 "llspeakers.h" + +#include "llagent.h" +#include "llappviewer.h" +#include "llmutelist.h" +#include "llsdutil.h" +#include "lluicolortable.h" +#include "llviewerobjectlist.h" +#include "llvoavatar.h" +#include "llworld.h" + +const F32 SPEAKER_TIMEOUT = 10.f; // seconds of not being on voice channel before removed from list of active speakers +const LLColor4 INACTIVE_COLOR(0.3f, 0.3f, 0.3f, 0.5f); +const LLColor4 ACTIVE_COLOR(0.5f, 0.5f, 0.5f, 1.f); + +LLSpeaker::LLSpeaker(const LLUUID& id, const std::string& name, const ESpeakerType type) :  +	mStatus(LLSpeaker::STATUS_TEXT_ONLY), +	mLastSpokeTime(0.f),  +	mSpeechVolume(0.f),  +	mHasSpoken(FALSE), +	mHasLeftCurrentCall(FALSE), +	mDotColor(LLColor4::white), +	mID(id), +	mTyping(FALSE), +	mSortIndex(0), +	mType(type), +	mIsModerator(FALSE), +	mModeratorMutedVoice(FALSE), +	mModeratorMutedText(FALSE) +{ +	if (name.empty() && type == SPEAKER_AGENT) +	{ +		lookupName(); +	} +	else +	{ +		mDisplayName = name; +	} + +	gVoiceClient->setUserVolume(id, LLMuteList::getInstance()->getSavedResidentVolume(id)); + +	mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +} + + +void LLSpeaker::lookupName() +{ +	gCacheName->get(mID, FALSE, boost::bind(&LLSpeaker::onAvatarNameLookup, this, _1, _2, _3, _4)); +} + +void LLSpeaker::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) +{ +	mDisplayName = first + " " + last; +} + +LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) +: LLEvent(source, "Speaker text moderation event") +{ +} + +LLSD LLSpeakerTextModerationEvent::getValue() +{ +	return std::string("text"); +} + + +LLSpeakerVoiceModerationEvent::LLSpeakerVoiceModerationEvent(LLSpeaker* source) +: LLEvent(source, "Speaker voice moderation event") +{ +} + +LLSD LLSpeakerVoiceModerationEvent::getValue() +{ +	return std::string("voice"); +} + +LLSpeakerListChangeEvent::LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id) +: LLEvent(source, "Speaker added/removed from speaker mgr"), +  mSpeakerID(speaker_id) +{ +} + +LLSD LLSpeakerListChangeEvent::getValue() +{ +	return mSpeakerID; +} + +// helper sort class +struct LLSortRecentSpeakers +{ +	bool operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const; +}; + +bool LLSortRecentSpeakers::operator()(const LLPointer<LLSpeaker> lhs, const LLPointer<LLSpeaker> rhs) const +{ +	// Sort first on status +	if (lhs->mStatus != rhs->mStatus)  +	{ +		return (lhs->mStatus < rhs->mStatus); +	} + +	// and then on last speaking time +	if(lhs->mLastSpokeTime != rhs->mLastSpokeTime) +	{ +		return (lhs->mLastSpokeTime > rhs->mLastSpokeTime); +	} +	 +	// and finally (only if those are both equal), on name. +	return(	lhs->mDisplayName.compare(rhs->mDisplayName) < 0 ); +} + + +// +// LLSpeakerMgr +// + +LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) :  +	mVoiceChannel(channelp) +{ +} + +LLSpeakerMgr::~LLSpeakerMgr() +{ +} + +LLPointer<LLSpeaker> LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) +{ +	if (id.isNull()) return NULL; + +	LLPointer<LLSpeaker> speakerp; +	if (mSpeakers.find(id) == mSpeakers.end()) +	{ +		speakerp = new LLSpeaker(id, name, type); +		speakerp->mStatus = status; +		mSpeakers.insert(std::make_pair(speakerp->mID, speakerp)); +		mSpeakersSorted.push_back(speakerp); +		fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "add"); +	} +	else +	{ +		speakerp = findSpeaker(id); +		if (speakerp.notNull()) +		{ +			// keep highest priority status (lowest value) instead of overriding current value +			speakerp->mStatus = llmin(speakerp->mStatus, status); +			speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			// RN: due to a weird behavior where IMs from attached objects come from the wearer's agent_id +			// we need to override speakers that we think are objects when we find out they are really +			// residents +			if (type == LLSpeaker::SPEAKER_AGENT) +			{ +				speakerp->mType = LLSpeaker::SPEAKER_AGENT; +				speakerp->lookupName(); +			} +		} +	} + +	return speakerp; +} + +void LLSpeakerMgr::update(BOOL resort_ok) +{ +	if (!gVoiceClient) +	{ +		return; +	} +	 +	LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor"); +	LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor"); + +	if(resort_ok) // only allow list changes when user is not interacting with it +	{ +		updateSpeakerList(); +	} + +	// update status of all current speakers +	BOOL voice_channel_active = (!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		 +		speaker_map_t::iterator  cur_speaker_it = speaker_it++; + +		if (voice_channel_active && gVoiceClient->getVoiceEnabled(speaker_id)) +		{ +			speakerp->mSpeechVolume = gVoiceClient->getCurrentPower(speaker_id); +			BOOL moderator_muted_voice = gVoiceClient->getIsModeratorMuted(speaker_id); +			if (moderator_muted_voice != speakerp->mModeratorMutedVoice) +			{ +				speakerp->mModeratorMutedVoice = moderator_muted_voice; +				speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp)); +			} + +			if (gVoiceClient->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_MUTED; +			} +			else if (gVoiceClient->getIsSpeaking(speaker_id)) +			{ +				// reset inactivity expiration +				if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING) +				{ +					speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); +					speakerp->mHasSpoken = TRUE; +				} +				speakerp->mStatus = LLSpeaker::STATUS_SPEAKING; +				// interpolate between active color and full speaking color based on power of speech output +				speakerp->mDotColor = speaking_color; +				if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL) +				{ +					speakerp->mDotColor = overdriven_color; +				} +			} +			else +			{ +				speakerp->mSpeechVolume = 0.f; +				speakerp->mDotColor = ACTIVE_COLOR; + +				if (speakerp->mHasSpoken) +				{ +					// have spoken once, not currently speaking +					speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN; +				} +				else +				{ +					// default state for being in voice channel +					speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE; +				} +			} +		} +		// speaker no longer registered in voice channel, demote to text only +		else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL) +		{ +			if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL) +			{ +				// external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice) +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +			} +			else +			{ +				speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY; +				speakerp->mSpeechVolume = 0.f; +				speakerp->mDotColor = ACTIVE_COLOR; +			} +		} +	} + +	if(resort_ok)  // only allow list changes when user is not interacting with it +	{ +		// sort by status then time last spoken +		std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers()); +	} + +	// for recent speakers who are not currently speaking, show "recent" color dot for most recent +	// fading to "active" color + +	S32 recent_speaker_count = 0; +	S32 sort_index = 0; +	speaker_list_t::iterator sorted_speaker_it; +	for(sorted_speaker_it = mSpeakersSorted.begin();  +		sorted_speaker_it != mSpeakersSorted.end(); ) +	{ +		LLPointer<LLSpeaker> speakerp = *sorted_speaker_it; +		 +		// color code recent speakers who are not currently speaking +		if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN) +		{ +			speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f)); +			recent_speaker_count++; +		} + +		// stuff sort ordinal into speaker so the ui can sort by this value +		speakerp->mSortIndex = sort_index++; + +		// remove speakers that have been gone too long +		if (speakerp->mStatus == LLSpeaker::STATUS_NOT_IN_CHANNEL && speakerp->mActivityTimer.hasExpired()) +		{ +			fireEvent(new LLSpeakerListChangeEvent(this, speakerp->mID), "remove"); + +			mSpeakers.erase(speakerp->mID); +			sorted_speaker_it = mSpeakersSorted.erase(sorted_speaker_it); +		} +		else +		{ +			++sorted_speaker_it; +		} +	} +} + +void LLSpeakerMgr::updateSpeakerList() +{ +	// are we bound to the currently active voice channel? +	if ((!mVoiceChannel && gVoiceClient->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) +	{ +		LLVoiceClient::participantMap* participants = gVoiceClient->getParticipantList(); +		if(participants) +		{ +			LLVoiceClient::participantMap::iterator participant_it; + +			// add new participants to our list of known speakers +			for (participant_it = participants->begin(); participant_it != participants->end(); ++participant_it) +			{ +				LLVoiceClient::participantState* participantp = participant_it->second; +				setSpeaker(participantp->mAvatarID, participantp->mDisplayName, LLSpeaker::STATUS_VOICE_ACTIVE, (participantp->isAvatar()?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); +			} +		} +	} +} + +LLPointer<LLSpeaker> LLSpeakerMgr::findSpeaker(const LLUUID& speaker_id) +{ +	speaker_map_t::iterator found_it = mSpeakers.find(speaker_id); +	if (found_it == mSpeakers.end()) +	{ +		return NULL; +	} +	return found_it->second; +} + +void LLSpeakerMgr::getSpeakerList(speaker_list_t* speaker_list, BOOL include_text) +{ +	speaker_list->clear(); +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLPointer<LLSpeaker> speakerp = speaker_it->second; +		// what about text only muted or inactive? +		if (include_text || speakerp->mStatus != LLSpeaker::STATUS_TEXT_ONLY) +		{ +			speaker_list->push_back(speakerp); +		} +	} +} + +const LLUUID LLSpeakerMgr::getSessionID()  +{  +	return mVoiceChannel->getSessionID();  +} + + +void LLSpeakerMgr::setSpeakerTyping(const LLUUID& speaker_id, BOOL typing) +{ +	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); +	if (speakerp.notNull()) +	{ +		speakerp->mTyping = typing; +	} +} + +// speaker has chatted via either text or voice +void LLSpeakerMgr::speakerChatted(const LLUUID& speaker_id) +{ +	LLPointer<LLSpeaker> speakerp = findSpeaker(speaker_id); +	if (speakerp.notNull()) +	{ +		speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32(); +		speakerp->mHasSpoken = TRUE; +	} +} + +BOOL LLSpeakerMgr::isVoiceActive() +{ +	// mVoiceChannel = NULL means current voice channel, whatever it is +	return LLVoiceClient::voiceEnabled() && mVoiceChannel && mVoiceChannel->isActive(); +} + + +// +// LLIMSpeakerMgr +// +LLIMSpeakerMgr::LLIMSpeakerMgr(LLVoiceChannel* channel) : LLSpeakerMgr(channel) +{ +} + +void LLIMSpeakerMgr::updateSpeakerList() +{ +	// don't do normal updates which are pulled from voice channel +	// rely on user list reported by sim +	 +	// We need to do this to allow PSTN callers into group chats to show in the list. +	LLSpeakerMgr::updateSpeakerList(); +	 +	return; +} + +void LLIMSpeakerMgr::setSpeakers(const LLSD& speakers) +{ +	if ( !speakers.isMap() ) return; + +	if ( speakers.has("agent_info") && speakers["agent_info"].isMap() ) +	{ +		LLSD::map_const_iterator speaker_it; +		for(speaker_it = speakers["agent_info"].beginMap(); +			speaker_it != speakers["agent_info"].endMap(); +			++speaker_it) +		{ +			LLUUID agent_id(speaker_it->first); + +			LLPointer<LLSpeaker> speakerp = setSpeaker( +				agent_id, +				LLStringUtil::null, +				LLSpeaker::STATUS_TEXT_ONLY); + +			if ( speaker_it->second.isMap() ) +			{ +				speakerp->mIsModerator = speaker_it->second["is_moderator"]; +				speakerp->mModeratorMutedText = +					speaker_it->second["mutes"]["text"]; +			} +		} +	} +	else if ( speakers.has("agents" ) && speakers["agents"].isArray() ) +	{ +		//older, more decprecated way.  Need here for +		//using older version of servers +		LLSD::array_const_iterator speaker_it; +		for(speaker_it = speakers["agents"].beginArray(); +			speaker_it != speakers["agents"].endArray(); +			++speaker_it) +		{ +			const LLUUID agent_id = (*speaker_it).asUUID(); + +			LLPointer<LLSpeaker> speakerp = setSpeaker( +				agent_id, +				LLStringUtil::null, +				LLSpeaker::STATUS_TEXT_ONLY); +		} +	} +} + +void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) +{ +	if ( !update.isMap() ) return; + +	if ( update.has("agent_updates") && update["agent_updates"].isMap() ) +	{ +		LLSD::map_const_iterator update_it; +		for( +			update_it = update["agent_updates"].beginMap(); +			update_it != update["agent_updates"].endMap(); +			++update_it) +		{ +			LLUUID agent_id(update_it->first); +			LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + +			LLSD agent_data = update_it->second; + +			if (agent_data.isMap() && agent_data.has("transition")) +			{ +				if (agent_data["transition"].asString() == "LEAVE" && speakerp.notNull()) +				{ +					speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +					speakerp->mDotColor = INACTIVE_COLOR; +					speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +				} +				else if (agent_data["transition"].asString() == "ENTER") +				{ +					// add or update speaker +					speakerp = setSpeaker(agent_id); +				} +				else +				{ +					llwarns << "bad membership list update " << ll_print_sd(agent_data["transition"]) << llendl; +				} +			} + +			if (speakerp.isNull()) continue; + +			// should have a valid speaker from this point on +			if (agent_data.isMap() && agent_data.has("info")) +			{ +				LLSD agent_info = agent_data["info"]; + +				if (agent_info.has("is_moderator")) +				{ +					speakerp->mIsModerator = agent_info["is_moderator"]; +				} + +				if (agent_info.has("mutes")) +				{ +					speakerp->mModeratorMutedText = agent_info["mutes"]["text"]; +				} +			} +		} +	} +	else if ( update.has("updates") && update["updates"].isMap() ) +	{ +		LLSD::map_const_iterator update_it; +		for ( +			update_it = update["updates"].beginMap(); +			update_it != update["updates"].endMap(); +			++update_it) +		{ +			LLUUID agent_id(update_it->first); +			LLPointer<LLSpeaker> speakerp = findSpeaker(agent_id); + +			std::string agent_transition = update_it->second.asString(); +			if (agent_transition == "LEAVE" && speakerp.notNull()) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +				speakerp->mDotColor = INACTIVE_COLOR; +				speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			} +			else if ( agent_transition == "ENTER") +			{ +				// add or update speaker +				speakerp = setSpeaker(agent_id); +			} +			else +			{ +				llwarns << "bad membership list update " +						<< agent_transition << llendl; +			} +		} +	} +} + + +// +// LLActiveSpeakerMgr +// + +LLActiveSpeakerMgr::LLActiveSpeakerMgr() : LLSpeakerMgr(NULL) +{ +} + +void LLActiveSpeakerMgr::updateSpeakerList() +{ +	// point to whatever the current voice channel is +	mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); + +	// always populate from active voice channel +	if (LLVoiceChannel::getCurrentVoiceChannel() != mVoiceChannel) +	{ +		fireEvent(new LLSpeakerListChangeEvent(this, LLUUID::null), "clear"); +		mSpeakers.clear(); +		mSpeakersSorted.clear(); +		mVoiceChannel = LLVoiceChannel::getCurrentVoiceChannel(); +	} +	LLSpeakerMgr::updateSpeakerList(); + +	// clean up text only speakers +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) +		{ +			// automatically flag text only speakers for removal +			speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +		} +	} + +} + + + +// +// LLLocalSpeakerMgr +// + +LLLocalSpeakerMgr::LLLocalSpeakerMgr() : LLSpeakerMgr(LLVoiceChannelProximal::getInstance()) +{ +} + +LLLocalSpeakerMgr::~LLLocalSpeakerMgr () +{ +} + +void LLLocalSpeakerMgr::updateSpeakerList() +{ +	// pull speakers from voice channel +	LLSpeakerMgr::updateSpeakerList(); + +	if (gDisconnected)//the world is cleared. +	{ +		return ; +	} + +	// pick up non-voice speakers in chat range +	std::vector<LLUUID> avatar_ids; +	std::vector<LLVector3d> positions; +	LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); +	for(U32 i=0; i<avatar_ids.size(); i++) +	{ +		setSpeaker(avatar_ids[i]); +	} + +	// check if text only speakers have moved out of chat range +	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); ++speaker_it) +	{ +		LLUUID speaker_id = speaker_it->first; +		LLSpeaker* speakerp = speaker_it->second; +		if (speakerp->mStatus == LLSpeaker::STATUS_TEXT_ONLY) +		{ +			LLVOAvatar* avatarp = (LLVOAvatar*)gObjectList.findObject(speaker_id); +			if (!avatarp || dist_vec(avatarp->getPositionAgent(), gAgent.getPositionAgent()) > CHAT_NORMAL_RADIUS) +			{ +				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL; +				speakerp->mDotColor = INACTIVE_COLOR; +				speakerp->mActivityTimer.resetWithExpiry(SPEAKER_TIMEOUT); +			} +		} +	} +} diff --git a/indra/newview/llspeakers.h b/indra/newview/llspeakers.h new file mode 100644 index 0000000000..e0f22bff4f --- /dev/null +++ b/indra/newview/llspeakers.h @@ -0,0 +1,172 @@ +/**  + * @file llspeakers.h + * @brief Management interface for muting and controlling volume of residents currently speaking + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + *  + * Copyright (c) 2005-2009, 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$ + */ + +#ifndef LL_LLSPEAKERS_H +#define LL_LLSPEAKERS_H + +#include "llevent.h" +#include "llspeakers.h" +#include "llvoicechannel.h" + +class LLSpeakerMgr; + +// data for a given participant in a voice channel +class LLSpeaker : public LLRefCount, public LLOldEvents::LLObservable, public LLHandleProvider<LLSpeaker>, public boost::signals2::trackable +{ +public: +	typedef enum e_speaker_type +	{ +		SPEAKER_AGENT, +		SPEAKER_OBJECT, +		SPEAKER_EXTERNAL	// Speaker that doesn't map to an avatar or object (i.e. PSTN caller in a group) +	} ESpeakerType; + +	typedef enum e_speaker_status +	{ +		STATUS_SPEAKING, +		STATUS_HAS_SPOKEN, +		STATUS_VOICE_ACTIVE, +		STATUS_TEXT_ONLY, +		STATUS_NOT_IN_CHANNEL, +		STATUS_MUTED +	} ESpeakerStatus; + + +	LLSpeaker(const LLUUID& id, const std::string& name = LLStringUtil::null, const ESpeakerType type = SPEAKER_AGENT); +	~LLSpeaker() {}; +	void lookupName(); + +	void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); + +	ESpeakerStatus	mStatus;			// current activity status in speech group +	F32				mLastSpokeTime;		// timestamp when this speaker last spoke +	F32				mSpeechVolume;		// current speech amplitude (timea average rms amplitude?) +	std::string		mDisplayName;		// cache user name for this speaker +	LLFrameTimer	mActivityTimer;	// time out speakers when they are not part of current voice channel +	BOOL			mHasSpoken;			// has this speaker said anything this session? +	BOOL			mHasLeftCurrentCall;	// has this speaker left the current voice call? +	LLColor4		mDotColor; +	LLUUID			mID; +	BOOL			mTyping; +	S32				mSortIndex; +	ESpeakerType	mType; +	BOOL			mIsModerator; +	BOOL			mModeratorMutedVoice; +	BOOL			mModeratorMutedText; +}; + +class LLSpeakerTextModerationEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerTextModerationEvent(LLSpeaker* source); +	/*virtual*/ LLSD getValue(); +}; + +class LLSpeakerVoiceModerationEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerVoiceModerationEvent(LLSpeaker* source); +	/*virtual*/ LLSD getValue(); +}; + +class LLSpeakerListChangeEvent : public LLOldEvents::LLEvent +{ +public: +	LLSpeakerListChangeEvent(LLSpeakerMgr* source, const LLUUID& speaker_id); +	/*virtual*/ LLSD getValue(); + +private: +	const LLUUID& mSpeakerID; +}; + +class LLSpeakerMgr : public LLOldEvents::LLObservable +{ +public: +	LLSpeakerMgr(LLVoiceChannel* channelp); +	virtual ~LLSpeakerMgr(); + +	LLPointer<LLSpeaker> findSpeaker(const LLUUID& avatar_id); +	void update(BOOL resort_ok); +	void setSpeakerTyping(const LLUUID& speaker_id, BOOL typing); +	void speakerChatted(const LLUUID& speaker_id); +	LLPointer<LLSpeaker> setSpeaker(const LLUUID& id,  +					const std::string& name = LLStringUtil::null,  +					LLSpeaker::ESpeakerStatus status = LLSpeaker::STATUS_TEXT_ONLY,  +					LLSpeaker::ESpeakerType = LLSpeaker::SPEAKER_AGENT); + +	BOOL isVoiceActive(); + +	typedef std::vector<LLPointer<LLSpeaker> > speaker_list_t; +	void getSpeakerList(speaker_list_t* speaker_list, BOOL include_text); +	LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } +	const LLUUID getSessionID(); + +protected: +	virtual void updateSpeakerList(); + +	typedef std::map<LLUUID, LLPointer<LLSpeaker> > speaker_map_t; +	speaker_map_t		mSpeakers; + +	speaker_list_t		mSpeakersSorted; +	LLFrameTimer		mSpeechTimer; +	LLVoiceChannel*		mVoiceChannel; +}; + +class LLIMSpeakerMgr : public LLSpeakerMgr +{ +public: +	LLIMSpeakerMgr(LLVoiceChannel* channel); +	 +	void updateSpeakers(const LLSD& update); +	void setSpeakers(const LLSD& speakers); +protected: +	virtual void updateSpeakerList(); +}; + +class LLActiveSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLActiveSpeakerMgr> +{ +public: +	LLActiveSpeakerMgr(); +protected: +	virtual void updateSpeakerList(); +}; + +class LLLocalSpeakerMgr : public LLSpeakerMgr, public LLSingleton<LLLocalSpeakerMgr> +{ +public: +	LLLocalSpeakerMgr(); +	~LLLocalSpeakerMgr (); +protected: +	virtual void updateSpeakerList(); +}; + +#endif // LL_LLSPEAKERS_H diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp index 86290e6695..93a931dc78 100644 --- a/indra/newview/llsyswellwindow.cpp +++ b/indra/newview/llsyswellwindow.cpp @@ -113,6 +113,12 @@ void LLSysWellWindow::connectListUpdaterToSignal(std::string notification_type)  }  //--------------------------------------------------------------------------------- +void LLSysWellWindow::onStartUpToastClick(S32 x, S32 y, MASK mask) +{ +	onChicletClick(); +} + +//---------------------------------------------------------------------------------  void LLSysWellWindow::onChicletClick()  {  	// 1 - remove StartUp toast and channel if present diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h index fa6a1abea4..cbc5f7358f 100644 --- a/indra/newview/llsyswellwindow.h +++ b/indra/newview/llsyswellwindow.h @@ -76,6 +76,7 @@ public:  	void onItemClose(LLSysWellItem* item);  	void onStoreToast(LLPanel* info_panel, LLUUID id);  	void onChicletClick(); +	void onStartUpToastClick(S32 x, S32 y, MASK mask);  	// size constants for the window and for its elements  	static const S32 MAX_WINDOW_HEIGHT		= 200; diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 17547cae39..5d9046ac90 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -804,8 +804,9 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,  	gGL.setColorMask(false, true);  	gGL.setSceneBlendType(LLRender::BT_REPLACE); +	  	// (Optionally) replace alpha with a single component image from a tga file. -	if (!info->mStaticAlphaFileName.empty() && mMaskLayerList.empty()) +	if (!info->mStaticAlphaFileName.empty())  	{  		LLGLSNoAlphaTest gls_no_alpha_test;  		gGL.flush(); diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index eba43d76a6..24824a095c 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -63,6 +63,7 @@ LLToast::LLToast(const LLToast::Params& p)  	mHideBtnEnabled(p.enable_hide_btn),  	mHideBtn(NULL),  	mNotification(p.notification), +	mIsHidden(false),  	mHideBtnPressed(false)  {  	LLUICtrlFactory::getInstance()->buildFloater(this, "panel_toast.xml", NULL); @@ -143,7 +144,8 @@ void LLToast::hide()  {  	setVisible(FALSE);  	mTimer.stop(); -	mOnFadeSignal(this); +	mIsHidden = true; +	mOnFadeSignal(this);   }  //-------------------------------------------------------------------------- @@ -159,9 +161,7 @@ void LLToast::tick()  {  	if(mCanFade)  	{ -		setVisible(FALSE); -		mTimer.stop(); -		mOnFadeSignal(this);  +		hide();  	}  } @@ -206,6 +206,16 @@ void LLToast::draw()  //--------------------------------------------------------------------------  void LLToast::setVisible(BOOL show)  { +	if(mIsHidden) +	{ +		// this toast is invisible after fade until its ScreenChannel will allow it +		// +		// (EXT-1849) according to this bug a toast can be resurrected from +		// invisible state if it faded during a teleportation +		// then it fades a second time and causes a crash +		return; +	} +  	if(show)  	{  		setBackgroundOpaque(TRUE); diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h index 1826c13ebc..0698c94880 100644 --- a/indra/newview/lltoast.h +++ b/indra/newview/lltoast.h @@ -125,6 +125,8 @@ public:  	void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; }  	//  	bool getCanBeStored() { return mCanBeStored; } +	// set whether this toast considered as hidden or not +	void setIsHidden( bool is_toast_hidden ) { mIsHidden = is_toast_hidden; }  	// Registers signals/callbacks for events @@ -164,6 +166,7 @@ private:  	bool		mCanBeStored;  	bool		mHideBtnEnabled;  	bool		mHideBtnPressed; +	bool		mIsHidden;  // this flag is TRUE when a toast has faded or was hidden with (x) button (EXT-1849)  };  } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 57a4117d5d..366e5602bd 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -42,7 +42,6 @@  #include "llconsole.h"  #include "llinventorymodel.h"  #include "llnotify.h" -#include "llimview.h"  #include "llgesturemgr.h"  #include "llinventorybridge.h" diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 02fda191be..8bd74dcb04 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -156,10 +156,10 @@ public:  	{  		if(!mInitialized && ! mime_type.empty())  		{ -			if (mMediaImpl->initializeMedia(mime_type)) +			if(mMediaImpl->initializeMedia(mime_type))  			{  				mInitialized = true; -				mMediaImpl->play(); +				mMediaImpl->loadURI();  			}  		}  	} @@ -267,10 +267,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s  			{  				needs_navigate = (media_entry->getCurrentURL() != previous_url);  			} -			else if(!media_entry->getHomeURL().empty()) -			{ -				needs_navigate = (media_entry->getHomeURL() != previous_url); -			}  		}  	}  	else @@ -293,8 +289,6 @@ viewer_media_t LLViewerMedia::updateMediaImpl(LLMediaEntry* media_entry, const s  	if(media_impl && needs_navigate)  	{  		std::string url = media_entry->getCurrentURL(); -		if(url.empty()) -			url = media_entry->getHomeURL();  		media_impl->navigateTo(url, "", true, true);  	} @@ -639,13 +633,14 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  	mUsedInUI(false),  	mHasFocus(false),  	mPriority(LLPluginClassMedia::PRIORITY_UNLOADED), -	mDoNavigateOnLoad(false), -	mDoNavigateOnLoadRediscoverType(false), -	mDoNavigateOnLoadServerRequest(false), +	mNavigateRediscoverType(false), +	mNavigateServerRequest(false),  	mMediaSourceFailed(false),  	mRequestedVolume(1.0f),  	mIsMuted(false),  	mNeedsMuteCheck(false), +	mPreviousMediaState(MEDIA_NONE), +	mPreviousMediaTime(0.0f),  	mIsUpdated(false)  {  @@ -716,7 +711,6 @@ bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type)  		mMimeType = mime_type;  	} -	// play();  	return (mMediaSource != NULL);  } @@ -729,16 +723,13 @@ void LLViewerMediaImpl::createMediaSource()  		return;  	} -	if(mDoNavigateOnLoad) +	if(! mMediaURL.empty())  	{ -		if(! mMediaURL.empty()) -		{ -			navigateTo(mMediaURL, mMimeType, mDoNavigateOnLoadRediscoverType, mDoNavigateOnLoadServerRequest); -		} -		else if(! mMimeType.empty()) -		{ -			initializeMedia(mMimeType); -		} +		navigateInternal(); +	} +	else if(! mMimeType.empty()) +	{ +		initializeMedia(mMimeType);  	}  } @@ -869,6 +860,46 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)  	return false;  } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::loadURI() +{ +	if(mMediaSource) +	{ +		mMediaSource->loadURI( mMediaURL ); + +		if(mPreviousMediaState == MEDIA_PLAYING) +		{ +			// This media was playing before this instance was unloaded. + +			if(mPreviousMediaTime != 0.0f) +			{ +				// Seek back to where we left off, if possible. +				seek(mPreviousMediaTime); +			} +			 +			start(); +		} +		else if(mPreviousMediaState == MEDIA_PAUSED) +		{ +			// This media was paused before this instance was unloaded. + +			if(mPreviousMediaTime != 0.0f) +			{ +				// Seek back to where we left off, if possible. +				seek(mPreviousMediaTime); +			} +			 +			pause(); +		} +		else +		{ +			// No relevant previous media play state -- if we're loading the URL, we want to start playing. +			start(); +		} +	} +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::setSize(int width, int height)  {  	mMediaWidth = width; @@ -882,24 +913,21 @@ void LLViewerMediaImpl::setSize(int width, int height)  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::play()  { -	// first stop any previously playing media -	// stop(); - -	// mMediaSource->addObserver( this ); +	// If the media source isn't there, try to initialize it and load an URL.  	if(mMediaSource == NULL)  	{ -	 	if(!initializePlugin(mMimeType)) +	 	if(!initializeMedia(mMimeType))  		{  			// This may be the case where the plugin's priority is PRIORITY_UNLOADED  			return;  		} +		 +		// Only do this if the media source was just loaded. +		loadURI();  	} -	mMediaSource->loadURI( mMediaURL ); -	if(/*mMediaSource->pluginSupportsMediaTime()*/ true) -	{ -		start(); -	} +	// always start the media +	start();  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1165,27 +1193,21 @@ void LLViewerMediaImpl::navigateHome()  //////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type,  bool rediscover_type, bool server_request)  { -	if(server_request) -	{ -		setNavState(MEDIANAVSTATE_SERVER_SENT); -	} -	else +	if(mMediaURL != url)  	{ -		setNavState(MEDIANAVSTATE_NONE); +		// Don't carry media play state across distinct URLs. +		resetPreviousMediaState();  	}  	// Always set the current URL and MIME type.  	mMediaURL = url;  	mMimeType = mime_type; -	// If the current URL is not null, make the instance do a navigate on load. -	mDoNavigateOnLoad = !mMediaURL.empty(); -  	// if mime type discovery was requested, we'll need to do it when the media loads -	mDoNavigateOnLoadRediscoverType = rediscover_type; +	mNavigateRediscoverType = rediscover_type;  	// and if this was a server request, the navigate on load will also need to be one. -	mDoNavigateOnLoadServerRequest = server_request; +	mNavigateServerRequest = server_request;  	// An explicit navigate resets the "failed" flag.  	mMediaSourceFailed = false; @@ -1193,7 +1215,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  	if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)  	{  		// Helpful to have media urls in log file. Shouldn't be spammy. -		llinfos << "UNLOADED media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; +		llinfos << "NOT LOADING media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl;  		// This impl should not be loaded at this time.  		LL_DEBUGS("PluginPriority") << this << "Not loading (PRIORITY_UNLOADED)" << LL_ENDL; @@ -1201,10 +1223,24 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  		return;  	} +	navigateInternal(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateInternal() +{  	// Helpful to have media urls in log file. Shouldn't be spammy. -	llinfos << "media id= " << mTextureId << " url=" << url << " mime_type=" << mime_type << llendl; -	 -	 +	llinfos << "media id= " << mTextureId << " url=" << mMediaURL << " mime_type=" << mMimeType << llendl; + +	if(mNavigateServerRequest) +	{ +		setNavState(MEDIANAVSTATE_SERVER_SENT); +	} +	else +	{ +		setNavState(MEDIANAVSTATE_NONE); +	} +			  	// If the caller has specified a non-empty MIME type, look that up in our MIME types list.  	// If we have a plugin for that MIME type, use that instead of attempting auto-discovery.  	// This helps in supporting legacy media content where the server the media resides on returns a bogus MIME type @@ -1216,11 +1252,11 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  		if(!plugin_basename.empty())  		{  			// We have a plugin for this mime type -			rediscover_type = false; +			mNavigateRediscoverType = false;  		}  	} -	if(rediscover_type) +	if(mNavigateRediscoverType)  	{  		LLURI uri(mMediaURL); @@ -1236,7 +1272,7 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  			// We use "data" internally for a text/html url for loading the login screen  			if(initializeMedia("text/html"))  			{ -				mMediaSource->loadURI( mMediaURL ); +				loadURI();  			}  		}  		else @@ -1244,24 +1280,18 @@ void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mi  			// This catches 'rtsp://' urls  			if(initializeMedia(scheme))  			{ -				mMediaSource->loadURI( mMediaURL ); +				loadURI();  			}  		}  	} -	else if (mMediaSource) +	else if(initializeMedia(mMimeType))  	{ -		mMediaSource->loadURI( mMediaURL ); -	} -	else if(initializeMedia(mime_type) && mMediaSource) -	{ -		mMediaSource->loadURI( mMediaURL ); +		loadURI();  	}  	else  	{ -		LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; -		return; +		LL_WARNS("Media") << "Couldn't navigate to: " << mMediaURL << " as there is no media type for: " << mMimeType << LL_ENDL;  	} -  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1390,6 +1420,7 @@ void LLViewerMediaImpl::update()  	if(mMediaSource->isPluginExited())  	{ +		resetPreviousMediaState();  		destroyMediaSource();  		return;  	} @@ -1586,6 +1617,14 @@ bool LLViewerMediaImpl::hasMedia()  }  ////////////////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaImpl::resetPreviousMediaState() +{ +	mPreviousMediaState = MEDIA_NONE; +	mPreviousMediaTime = 0.0f; +} + +//////////////////////////////////////////////////////////////////////////////////////////  void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginClassMediaOwner::EMediaEvent event)  {  	switch(event) @@ -1595,6 +1634,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			// The plugin failed to load properly.  Make sure the timer doesn't retry.  			// TODO: maybe mark this plugin as not loadable somehow?  			mMediaSourceFailed = true; + +			// Reset the last known state of the media to defaults. +			resetPreviousMediaState();  			// TODO: may want a different message for this case?  			LLSD args; @@ -1608,6 +1650,9 @@ void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* plugin, LLPluginCla  			// The plugin crashed.  			mMediaSourceFailed = true; +			// Reset the last known state of the media to defaults. +			resetPreviousMediaState(); +  			LLSD args;  			args["PLUGIN"] = LLMIMETypes::implType(mMimeType);  			// SJB: This is getting called every frame if the plugin fails to load, continuously respawining the alert! @@ -1833,11 +1878,11 @@ void LLViewerMediaImpl::setUsedInUI(bool used_in_ui)  	{  		if(getVisible())  		{ -			mPriority = LLPluginClassMedia::PRIORITY_NORMAL; +			setPriority(LLPluginClassMedia::PRIORITY_NORMAL);  		}  		else  		{ -			mPriority = LLPluginClassMedia::PRIORITY_HIDDEN; +			setPriority(LLPluginClassMedia::PRIORITY_HIDDEN);  		}  		createMediaSource(); @@ -1858,6 +1903,15 @@ F64 LLViewerMediaImpl::getCPUUsage() const  void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)  { +	if(mPriority != priority) +	{ +		LL_INFOS("PluginPriority") +			<< "changing priority of media id " << mTextureId +			<< " from " << LLPluginClassMedia::priorityToString(mPriority) +			<< " to " << LLPluginClassMedia::priorityToString(priority) +			<< LL_ENDL; +	} +	  	mPriority = priority;  	if(priority == LLPluginClassMedia::PRIORITY_UNLOADED) @@ -1865,6 +1919,11 @@ void LLViewerMediaImpl::setPriority(LLPluginClassMedia::EPriority priority)  		if(mMediaSource)  		{  			// Need to unload the media source +			 +			// First, save off previous media state +			mPreviousMediaState = mMediaSource->getStatus(); +			mPreviousMediaTime = mMediaSource->getCurrentTime(); +			  			destroyMediaSource();  		}  	} diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index b15314e954..4f0d39dd80 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -123,6 +123,7 @@ public:  	void setMediaType(const std::string& media_type);  	bool initializeMedia(const std::string& mime_type);  	bool initializePlugin(const std::string& media_type); +	void loadURI();  	LLPluginClassMedia* getMediaPlugin() { return mMediaSource; }  	void setSize(int width, int height); @@ -151,6 +152,7 @@ public:  	void navigateReload();  	void navigateHome();  	void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false, bool server_request = false); +	void navigateInternal();  	void navigateStop();  	bool handleKeyHere(KEY key, MASK mask);  	bool handleUnicodeCharHere(llwchar uni_char); @@ -174,6 +176,7 @@ public:  	bool isMediaPaused();  	bool hasMedia();  	bool isMediaFailed() { return mMediaSourceFailed; }; +	void resetPreviousMediaState();  	ECursorType getLastSetCursor() { return mLastSetCursor; }; @@ -287,14 +290,14 @@ public:  	bool mUsedInUI;  	bool mHasFocus;  	LLPluginClassMedia::EPriority mPriority; -	bool mDoNavigateOnLoad; -	bool mDoNavigateOnLoadRediscoverType; -	bool mDoNavigateOnLoadServerRequest; +	bool mNavigateRediscoverType; +	bool mNavigateServerRequest;  	bool mMediaSourceFailed;  	F32 mRequestedVolume;  	bool mIsMuted;  	bool mNeedsMuteCheck; - +	int mPreviousMediaState; +	F64 mPreviousMediaTime;  private:  	BOOL mIsUpdated ; diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp index b47e0b8406..5d0b77d4fb 100644 --- a/indra/newview/llviewermediafocus.cpp +++ b/indra/newview/llviewermediafocus.cpp @@ -35,7 +35,7 @@  //LLViewerMediaFocus  #include "llviewerobjectlist.h" -#include "llpanelmediahud.h" +#include "llpanelprimmediacontrols.h"  #include "llpluginclassmedia.h"  #include "llagent.h"  #include "lltoolpie.h" @@ -106,19 +106,19 @@ void LLViewerMediaFocus::setFocusFace(LLPointer<LLViewerObject> objectp, S32 fac  		// We must do this before  processing the media HUD zoom, or it may zoom to the wrong face.   		update(); -		if(mMediaHUD.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom()) +		if(mMediaControls.get() && face_auto_zoom && ! parcel->getMediaPreventCameraZoom())  		{ -			mMediaHUD.get()->resetZoomLevel(); -			mMediaHUD.get()->nextZoomLevel(); +			mMediaControls.get()->resetZoomLevel(); +			mMediaControls.get()->nextZoomLevel();  		}  	}  	else  	{  		if(mFocusedImplID != LLUUID::null)  		{ -			if(mMediaHUD.get()) +			if(mMediaControls.get())  			{ -				mMediaHUD.get()->resetZoomLevel(); +				mMediaControls.get()->resetZoomLevel();  			}  			gFocusMgr.setKeyboardFocus(NULL); @@ -327,20 +327,20 @@ void LLViewerMediaFocus::update()  		// We have an object and impl to point at.  		// Make sure the media HUD object exists. -		if(! mMediaHUD.get()) +		if(! mMediaControls.get())  		{ -			LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(); -			mMediaHUD = media_hud->getHandle(); -			gHUDView->addChild(media_hud);	 +			LLPanelPrimMediaControls* media_controls = new LLPanelPrimMediaControls(); +			mMediaControls = media_controls->getHandle(); +			gHUDView->addChild(media_controls);	  		} -		mMediaHUD.get()->setMediaFace(viewer_object, face, media_impl, normal); +		mMediaControls.get()->setMediaFace(viewer_object, face, media_impl, normal);  	}  	else  	{  		// The media HUD is no longer needed. -		if(mMediaHUD.get()) +		if(mMediaControls.get())  		{ -			mMediaHUD.get()->setMediaFace(NULL, 0, NULL); +			mMediaControls.get()->setMediaFace(NULL, 0, NULL);  		}  	}  } diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h index c77533ba5a..c1179de39d 100644 --- a/indra/newview/llviewermediafocus.h +++ b/indra/newview/llviewermediafocus.h @@ -40,7 +40,7 @@  #include "llselectmgr.h"  class LLViewerMediaImpl; -class LLPanelMediaHUD; +class LLPanelPrimMediaControls;  class LLViewerMediaFocus :   	public LLFocusableElement,  @@ -88,7 +88,7 @@ protected:  private: -	LLHandle<LLPanelMediaHUD> mMediaHUD; +	LLHandle<LLPanelPrimMediaControls> mMediaControls;  	LLUUID mFocusedObjectID;  	S32 mFocusedObjectFace; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 058f44ef57..864cf9d57b 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3483,7 +3483,6 @@ void set_god_level(U8 god_level)  {  	U8 old_god_level = gAgent.getGodLevel();  	gAgent.setGodLevel( god_level ); -	gIMMgr->refresh();  	LLViewerParcelMgr::getInstance()->notifyObservers();  	// God mode changes sim visibility diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 791ec07349..320f0f83ff 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -72,7 +72,6 @@  #include "llviewercontrol.h"  #include "lldrawpool.h"  #include "llfirstuse.h" -#include "llfloateractivespeakers.h"  #include "llfloateranimpreview.h"  #include "llfloaterbuycurrency.h"  #include "llfloaterbuyland.h" @@ -5680,7 +5679,7 @@ void onCovenantLoadComplete(LLVFS *vfs,  	LLPanelLandCovenant::updateCovenantText(covenant_text);  	LLFloaterBuyLand::updateCovenantText(covenant_text, asset_uuid); -	LLPanelPlaceInfo* panel = dynamic_cast<LLPanelPlaceInfo*>(LLSideTray::getInstance()->showPanel("panel_place_info", LLSD())); +	LLPanelPlaceInfo* panel = LLSideTray::getInstance()->findChild<LLPanelPlaceInfo>("panel_place_info");  	if (panel)  	{  		panel->updateCovenantText(covenant_text); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index f141d33729..9e1ba3f2ef 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -79,6 +79,7 @@  #include "timing.h"  #include "llviewermenu.h"  #include "lltooltip.h" +#include "llmediaentry.h"  // newview includes  #include "llagent.h" @@ -142,7 +143,6 @@  #include "llstatview.h"  #include "llsurface.h"  #include "llsurfacepatch.h" -#include "llimview.h"  #include "lltexlayer.h"  #include "lltextbox.h"  #include "lltexturecache.h" @@ -815,6 +815,33 @@ BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MAS    	// Always handled as far as the OS is concerned.  	return TRUE;  } + +BOOL LLViewerWindow::handleDrop( LLWindow *window,  LLCoordGL pos, MASK mask, std::string data ) +{ +	if (gSavedSettings.getBOOL("PrimMediaDragNDrop")) +	{ +		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; + +		llinfos << "### 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) +		{ +			LLSD media_data; +			/// XXX home URL too? +			media_data[LLMediaEntry::CURRENT_URL_KEY] = url; +			media_data[LLMediaEntry::AUTO_PLAY_KEY] = true; +			obj->syncMediaData(object_face, media_data, true, true); +			obj->sendMediaDataUpdate(); +		} +	} +  	// Always handled as far as the OS is concerned. +	return TRUE; +}  BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask)  { diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index d7c403739e..cf024df9bf 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -170,7 +170,8 @@ public:  	/*virtual*/ BOOL handleRightMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask);  	/*virtual*/ BOOL handleMiddleMouseDown(LLWindow *window,  LLCoordGL pos, MASK mask);  	/*virtual*/ BOOL handleMiddleMouseUp(LLWindow *window,  LLCoordGL pos, MASK mask); -	/*virtual*/ void handleMouseMove(LLWindow *window,  LLCoordGL pos, MASK mask); +	/*virtual*/ BOOL handleDrop(LLWindow *window,  LLCoordGL pos, MASK mask, std::string data); +				void handleMouseMove(LLWindow *window,  LLCoordGL pos, MASK mask);  	/*virtual*/ void handleMouseLeave(LLWindow *window);  	/*virtual*/ void handleResize(LLWindow *window,  S32 x,  S32 y);  	/*virtual*/ void handleFocus(LLWindow *window); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index a402aff8ab..f9c95afc31 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -6400,6 +6400,11 @@ LLBBox LLVOAvatar::getHUDBBox() const  				 ++attachment_iter)  			{  				const LLViewerObject* attached_object = (*attachment_iter); +				if (attached_object == NULL) +				{ +					llwarns << "HUD attached object is NULL!" << llendl; +					continue; +				}  				// initialize bounding box to contain identity orientation and center point for attached object  				bbox.addPointLocal(attached_object->getPosition());  				// add rotated bounding box for attached object diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp new file mode 100644 index 0000000000..96fcf61e62 --- /dev/null +++ b/indra/newview/llvoicechannel.cpp @@ -0,0 +1,872 @@ +/**  + * @file llvoicechannel.cpp + * @brief Voice Channel related classes + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, 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 "llagent.h" +#include "llfloaterreg.h" +#include "llimview.h" +#include "llnotifications.h" +#include "llpanel.h" +#include "llrecentpeople.h" +#include "llviewercontrol.h" +#include "llvoicechannel.h" + + +LLVoiceChannel::voice_channel_map_t LLVoiceChannel::sVoiceChannelMap; +LLVoiceChannel::voice_channel_map_uri_t LLVoiceChannel::sVoiceChannelURIMap; +LLVoiceChannel* LLVoiceChannel::sCurrentVoiceChannel = NULL; +LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; + +BOOL LLVoiceChannel::sSuspended = FALSE; + +// +// Constants +// +const U32 DEFAULT_RETRIES_COUNT = 3; + + +class LLVoiceCallCapResponder : public LLHTTPClient::Responder +{ +public: +	LLVoiceCallCapResponder(const LLUUID& session_id) : mSessionID(session_id) {}; + +	virtual void error(U32 status, const std::string& reason);	// called with bad status codes +	virtual void result(const LLSD& content); + +private: +	LLUUID mSessionID; +}; + + +void LLVoiceCallCapResponder::error(U32 status, const std::string& reason) +{ +	llwarns << "LLVoiceCallCapResponder::error(" +		<< status << ": " << reason << ")" +		<< llendl; +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if ( channelp ) +	{ +		if ( 403 == status ) +		{ +			//403 == no ability +			LLNotifications::instance().add( +				"VoiceNotAllowed", +				channelp->getNotifyArgs()); +		} +		else +		{ +			LLNotifications::instance().add( +				"VoiceCallGenericError", +				channelp->getNotifyArgs()); +		} +		channelp->deactivate(); +	} +} + +void LLVoiceCallCapResponder::result(const LLSD& content) +{ +	LLVoiceChannel* channelp = LLVoiceChannel::getChannelByID(mSessionID); +	if (channelp) +	{ +		//*TODO: DEBUG SPAM +		LLSD::map_const_iterator iter; +		for(iter = content.beginMap(); iter != content.endMap(); ++iter) +		{ +			llinfos << "LLVoiceCallCapResponder::result got "  +				<< iter->first << llendl; +		} + +		channelp->setChannelInfo( +			content["voice_credentials"]["channel_uri"].asString(), +			content["voice_credentials"]["channel_credentials"].asString()); +	} +} + +// +// LLVoiceChannel +// +LLVoiceChannel::LLVoiceChannel(const LLUUID& session_id, const std::string& session_name) :  +	mSessionID(session_id),  +	mState(STATE_NO_CHANNEL_INFO),  +	mSessionName(session_name), +	mIgnoreNextSessionLeave(FALSE) +{ +	mNotifyArgs["VOICE_CHANNEL_NAME"] = mSessionName; + +	if (!sVoiceChannelMap.insert(std::make_pair(session_id, this)).second) +	{ +		// a voice channel already exists for this session id, so this instance will be orphaned +		// the end result should simply be the failure to make voice calls +		llwarns << "Duplicate voice channels registered for session_id " << session_id << llendl; +	} + +	LLVoiceClient::getInstance()->addObserver(this); +} + +LLVoiceChannel::~LLVoiceChannel() +{ +	// Don't use LLVoiceClient::getInstance() here -- this can get called during atexit() time and that singleton MAY have already been destroyed. +	if(gVoiceClient) +	{ +		gVoiceClient->removeObserver(this); +	} +	 +	sVoiceChannelMap.erase(mSessionID); +	sVoiceChannelURIMap.erase(mURI); +} + +void LLVoiceChannel::setChannelInfo( +	const std::string& uri, +	const std::string& credentials) +{ +	setURI(uri); + +	mCredentials = credentials; + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		if (mURI.empty()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty URI for channel " << mSessionName << llendl; +			deactivate(); +		} +		else if (mCredentials.empty()) +		{ +			LLNotifications::instance().add("VoiceChannelJoinFailed", mNotifyArgs); +			llwarns << "Received empty credentials for channel " << mSessionName << llendl; +			deactivate(); +		} +		else +		{ +			setState(STATE_READY); + +			// if we are supposed to be active, reconnect +			// this will happen on initial connect, as we request credentials on first use +			if (sCurrentVoiceChannel == this) +			{ +				// just in case we got new channel info while active +				// should move over to new channel +				activate(); +			} +		} +	} +} + +void LLVoiceChannel::onChange(EStatusType type, const std::string &channelURI, bool proximal) +{ +	if (channelURI != mURI) +	{ +		return; +	} + +	if (type < BEGIN_ERROR_STATUS) +	{ +		handleStatusChange(type); +	} +	else +	{ +		handleError(type); +	} +} + +void LLVoiceChannel::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LOGIN_RETRY: +		//mLoginNotificationHandle = LLNotifyBox::showXml("VoiceLoginRetry")->getHandle(); +		LLNotifications::instance().add("VoiceLoginRetry"); +		break; +	case STATUS_LOGGED_IN: +		//if (!mLoginNotificationHandle.isDead()) +		//{ +		//	LLNotifyBox* notifyp = (LLNotifyBox*)mLoginNotificationHandle.get(); +		//	if (notifyp) +		//	{ +		//		notifyp->close(); +		//	} +		//	mLoginNotificationHandle.markDead(); +		//} +		break; +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			// if forceably removed from channel +			// update the UI and revert to default channel +			LLNotifications::instance().add("VoiceChannelDisconnected", mNotifyArgs); +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		break; +	case STATUS_JOINING: +		if (callStarted()) +		{ +			setState(STATE_RINGING); +		} +		break; +	case STATUS_JOINED: +		if (callStarted()) +		{ +			setState(STATE_CONNECTED); +		} +	default: +		break; +	} +} + +// default behavior is to just deactivate channel +// derived classes provide specific error messages +void LLVoiceChannel::handleError(EStatusType type) +{ +	deactivate(); +	setState(STATE_ERROR); +} + +BOOL LLVoiceChannel::isActive() +{  +	// only considered active when currently bound channel matches what our channel +	return callStarted() && LLVoiceClient::getInstance()->getCurrentChannel() == mURI;  +} + +BOOL LLVoiceChannel::callStarted() +{ +	return mState >= STATE_CALL_STARTED; +} + +void LLVoiceChannel::deactivate() +{ +	if (mState >= STATE_RINGING) +	{ +		// ignore session leave event +		mIgnoreNextSessionLeave = TRUE; +	} + +	if (callStarted()) +	{ +		setState(STATE_HUNG_UP); +		// mute the microphone if required when returning to the proximal channel +		if (gSavedSettings.getBOOL("AutoDisengageMic") && sCurrentVoiceChannel == this) +		{ +			gSavedSettings.setBOOL("PTTCurrentlyEnabled", true); +		} +	} + +	if (sCurrentVoiceChannel == this) +	{ +		// default channel is proximal channel +		sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); +		sCurrentVoiceChannel->activate(); +	} +} + +void LLVoiceChannel::activate() +{ +	if (callStarted()) +	{ +		return; +	} + +	// deactivate old channel and mark ourselves as the active one +	if (sCurrentVoiceChannel != this) +	{ +		// mark as current before deactivating the old channel to prevent +		// activating the proximal channel between IM calls +		LLVoiceChannel* old_channel = sCurrentVoiceChannel; +		sCurrentVoiceChannel = this; +		if (old_channel) +		{ +			old_channel->deactivate(); +		} +	} + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		// responsible for setting status to active +		getChannelInfo(); +	} +	else +	{ +		setState(STATE_CALL_STARTED); +	} +} + +void LLVoiceChannel::getChannelInfo() +{ +	// pretend we have everything we need +	if (sCurrentVoiceChannel == this) +	{ +		setState(STATE_CALL_STARTED); +	} +} + +//static  +LLVoiceChannel* LLVoiceChannel::getChannelByID(const LLUUID& session_id) +{ +	voice_channel_map_t::iterator found_it = sVoiceChannelMap.find(session_id); +	if (found_it == sVoiceChannelMap.end()) +	{ +		return NULL; +	} +	else +	{ +		return found_it->second; +	} +} + +//static  +LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) +{ +	voice_channel_map_uri_t::iterator found_it = sVoiceChannelURIMap.find(uri); +	if (found_it == sVoiceChannelURIMap.end()) +	{ +		return NULL; +	} +	else +	{ +		return found_it->second; +	} +} + +void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) +{ +	sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); +	mSessionID = new_session_id; +	sVoiceChannelMap.insert(std::make_pair(mSessionID, this)); +} + +void LLVoiceChannel::setURI(std::string uri) +{ +	sVoiceChannelURIMap.erase(mURI); +	mURI = uri; +	sVoiceChannelURIMap.insert(std::make_pair(mURI, this)); +} + +void LLVoiceChannel::setState(EState state) +{ +	switch(state) +	{ +	case STATE_RINGING: +		gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		break; +	case STATE_CONNECTED: +		gIMMgr->addSystemMessage(mSessionID, "connected", mNotifyArgs); +		break; +	case STATE_HUNG_UP: +		gIMMgr->addSystemMessage(mSessionID, "hang_up", mNotifyArgs); +		break; +	default: +		break; +	} + +	mState = state; +} + +void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) +{ +	if (state == STATE_CONNECTED) +	{ +		LLFloaterReg::showInstance("voice_call", mSessionID); +	} +	// By checking that current state is CONNECTED we make sure that the call window +	// has been shown, hence there's something to hide. This helps when user presses +	// the "End call" button right after initiating the call. +	// *TODO: move this check to LLFloaterCall? +	else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) +	{ +		LLFloaterReg::hideInstance("voice_call", mSessionID); +	} +} + +//static +void LLVoiceChannel::initClass() +{ +	sCurrentVoiceChannel = LLVoiceChannelProximal::getInstance(); +} + + +//static  +void LLVoiceChannel::suspend() +{ +	if (!sSuspended) +	{ +		sSuspendedVoiceChannel = sCurrentVoiceChannel; +		sSuspended = TRUE; +	} +} + +//static  +void LLVoiceChannel::resume() +{ +	if (sSuspended) +	{ +		if (gVoiceClient->voiceEnabled()) +		{ +			if (sSuspendedVoiceChannel) +			{ +				sSuspendedVoiceChannel->activate(); +			} +			else +			{ +				LLVoiceChannelProximal::getInstance()->activate(); +			} +		} +		sSuspended = FALSE; +	} +} + + +// +// LLVoiceChannelGroup +// + +LLVoiceChannelGroup::LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name) :  +	LLVoiceChannel(session_id, session_name) +{ +	mRetries = DEFAULT_RETRIES_COUNT; +	mIsRetrying = FALSE; +} + +void LLVoiceChannelGroup::deactivate() +{ +	if (callStarted()) +	{ +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +	LLVoiceChannel::deactivate(); +} + +void LLVoiceChannelGroup::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// we have the channel info, just need to use it now +		LLVoiceClient::getInstance()->setNonSpatialChannel( +			mURI, +			mCredentials); + +#if 0 // *TODO +		if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel +		{ +			// Add the party to the list of people with which we've recently interacted. +			for (/*people in the chat*/) +				LLRecentPeople::instance().add(buddy_id); +		} +#endif +	} +} + +void LLVoiceChannelGroup::getChannelInfo() +{ +	LLViewerRegion* region = gAgent.getRegion(); +	if (region) +	{ +		std::string url = region->getCapability("ChatSessionRequest"); +		LLSD data; +		data["method"] = "call"; +		data["session-id"] = mSessionID; +		LLHTTPClient::post(url, +						   data, +						   new LLVoiceCallCapResponder(mSessionID)); +	} +} + +void LLVoiceChannelGroup::setChannelInfo( +	const std::string& uri, +	const std::string& credentials) +{ +	setURI(uri); + +	mCredentials = credentials; + +	if (mState == STATE_NO_CHANNEL_INFO) +	{ +		if(!mURI.empty() && !mCredentials.empty()) +		{ +			setState(STATE_READY); + +			// if we are supposed to be active, reconnect +			// this will happen on initial connect, as we request credentials on first use +			if (sCurrentVoiceChannel == this) +			{ +				// just in case we got new channel info while active +				// should move over to new channel +				activate(); +			} +		} +		else +		{ +			//*TODO: notify user +			llwarns << "Received invalid credentials for channel " << mSessionName << llendl; +			deactivate(); +		} +	} +	else if ( mIsRetrying ) +	{ +		// we have the channel info, just need to use it now +		LLVoiceClient::getInstance()->setNonSpatialChannel( +			mURI, +			mCredentials); +	} +} + +void LLVoiceChannelGroup::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_JOINED: +		mRetries = 3; +		mIsRetrying = FALSE; +	default: +		break; +	} + +	LLVoiceChannel::handleStatusChange(type); +} + +void LLVoiceChannelGroup::handleError(EStatusType status) +{ +	std::string notify; +	switch(status) +	{ +	case ERROR_CHANNEL_LOCKED: +	case ERROR_CHANNEL_FULL: +		notify = "VoiceChannelFull"; +		break; +	case ERROR_NOT_AVAILABLE: +		//clear URI and credentials +		//set the state to be no info +		//and activate +		if ( mRetries > 0 ) +		{ +			mRetries--; +			mIsRetrying = TRUE; +			mIgnoreNextSessionLeave = TRUE; + +			getChannelInfo(); +			return; +		} +		else +		{ +			notify = "VoiceChannelJoinFailed"; +			mRetries = DEFAULT_RETRIES_COUNT; +			mIsRetrying = FALSE; +		} + +		break; + +	case ERROR_UNKNOWN: +	default: +		break; +	} + +	// notification +	if (!notify.empty()) +	{ +		LLNotificationPtr notification = LLNotifications::instance().add(notify, mNotifyArgs); +		// echo to im window +		gIMMgr->addMessage(mSessionID, LLUUID::null, SYSTEM_FROM, notification->getMessage()); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelGroup::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	switch(state) +	{ +	case STATE_RINGING: +		if ( !mIsRetrying ) +		{ +			gIMMgr->addSystemMessage(mSessionID, "ringing", mNotifyArgs); +		} + +		mState = state; +		break; +	default: +		LLVoiceChannel::setState(state); +	} +} + +// +// LLVoiceChannelProximal +// +LLVoiceChannelProximal::LLVoiceChannelProximal() :  +	LLVoiceChannel(LLUUID::null, LLStringUtil::null) +{ +	activate(); +} + +BOOL LLVoiceChannelProximal::isActive() +{ +	return callStarted() && LLVoiceClient::getInstance()->inProximalChannel();  +} + +void LLVoiceChannelProximal::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// this implicitly puts you back in the spatial channel +		LLVoiceClient::getInstance()->leaveNonSpatialChannel(); +	} +} + +void LLVoiceChannelProximal::onChange(EStatusType type, const std::string &channelURI, bool proximal) +{ +	if (!proximal) +	{ +		return; +	} + +	if (type < BEGIN_ERROR_STATUS) +	{ +		handleStatusChange(type); +	} +	else +	{ +		handleError(type); +	} +} + +void LLVoiceChannelProximal::handleStatusChange(EStatusType status) +{ +	// status updates +	switch(status) +	{ +	case STATUS_LEFT_CHANNEL: +		// do not notify user when leaving proximal channel +		return; +	case STATUS_VOICE_DISABLED: +		 gIMMgr->addSystemMessage(LLUUID::null, "unavailable", mNotifyArgs); +		return; +	default: +		break; +	} +	LLVoiceChannel::handleStatusChange(status); +} + + +void LLVoiceChannelProximal::handleError(EStatusType status) +{ +	std::string notify; +	switch(status) +	{ +	  case ERROR_CHANNEL_LOCKED: +	  case ERROR_CHANNEL_FULL: +		notify = "ProximalVoiceChannelFull"; +		break; +	  default: +		 break; +	} + +	// notification +	if (!notify.empty()) +	{ +		LLNotifications::instance().add(notify, mNotifyArgs); +	} + +	LLVoiceChannel::handleError(status); +} + +void LLVoiceChannelProximal::deactivate() +{ +	if (callStarted()) +	{ +		setState(STATE_HUNG_UP); +	} +} + + +// +// LLVoiceChannelP2P +// +LLVoiceChannelP2P::LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id) :  +		LLVoiceChannelGroup(session_id, session_name),  +		mOtherUserID(other_user_id), +		mReceivedCall(FALSE) +{ +	// make sure URI reflects encoded version of other user's agent id +	setURI(LLVoiceClient::getInstance()->sipURIFromID(other_user_id)); +} + +void LLVoiceChannelP2P::handleStatusChange(EStatusType type) +{ +	// status updates +	switch(type) +	{ +	case STATUS_LEFT_CHANNEL: +		if (callStarted() && !mIgnoreNextSessionLeave && !sSuspended) +		{ +			if (mState == STATE_RINGING) +			{ +				// other user declined call +				LLNotifications::instance().add("P2PCallDeclined", mNotifyArgs); +			} +			else +			{ +				// other user hung up +				LLNotifications::instance().add("VoiceChannelDisconnectedP2P", mNotifyArgs); +			} +			deactivate(); +		} +		mIgnoreNextSessionLeave = FALSE; +		return; +	default: +		break; +	} + +	LLVoiceChannel::handleStatusChange(type); +} + +void LLVoiceChannelP2P::handleError(EStatusType type) +{ +	switch(type) +	{ +	case ERROR_NOT_AVAILABLE: +		LLNotifications::instance().add("P2PCallNoAnswer", mNotifyArgs); +		break; +	default: +		break; +	} + +	LLVoiceChannel::handleError(type); +} + +void LLVoiceChannelP2P::activate() +{ +	if (callStarted()) return; + +	LLVoiceChannel::activate(); + +	if (callStarted()) +	{ +		// no session handle yet, we're starting the call +		if (mSessionHandle.empty()) +		{ +			mReceivedCall = FALSE; +			LLVoiceClient::getInstance()->callUser(mOtherUserID); +		} +		// otherwise answering the call +		else +		{ +			LLVoiceClient::getInstance()->answerInvite(mSessionHandle); +			 +			// using the session handle invalidates it.  Clear it out here so we can't reuse it by accident. +			mSessionHandle.clear(); +		} + +		// Add the party to the list of people with which we've recently interacted. +		LLRecentPeople::instance().add(mOtherUserID); +	} +} + +void LLVoiceChannelP2P::getChannelInfo() +{ +	// pretend we have everything we need, since P2P doesn't use channel info +	if (sCurrentVoiceChannel == this) +	{ +		setState(STATE_CALL_STARTED); +	} +} + +// receiving session from other user who initiated call +void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::string &inURI) +{  +	BOOL needs_activate = FALSE; +	if (callStarted()) +	{ +		// defer to lower agent id when already active +		if (mOtherUserID < gAgent.getID()) +		{ +			// pretend we haven't started the call yet, so we can connect to this session instead +			deactivate(); +			needs_activate = TRUE; +		} +		else +		{ +			// we are active and have priority, invite the other user again +			// under the assumption they will join this new session +			mSessionHandle.clear(); +			LLVoiceClient::getInstance()->callUser(mOtherUserID); +			return; +		} +	} + +	mSessionHandle = handle; + +	// The URI of a p2p session should always be the other end's SIP URI. +	if(!inURI.empty()) +	{ +		setURI(inURI); +	} +	else +	{ +		setURI(LLVoiceClient::getInstance()->sipURIFromID(mOtherUserID)); +	} +	 +	mReceivedCall = TRUE; + +	if (needs_activate) +	{ +		activate(); +	} +} + +void LLVoiceChannelP2P::setState(EState state) +{ +	// HACK: Open/close the call window if needed. +	toggleCallWindowIfNeeded(state); + +	// you only "answer" voice invites in p2p mode +	// so provide a special purpose message here +	if (mReceivedCall && state == STATE_RINGING) +	{ +		gIMMgr->addSystemMessage(mSessionID, "answering", mNotifyArgs); +		mState = state; +		return; +	} +	LLVoiceChannel::setState(state); +} diff --git a/indra/newview/llvoicechannel.h b/indra/newview/llvoicechannel.h new file mode 100644 index 0000000000..9966bdd5ab --- /dev/null +++ b/indra/newview/llvoicechannel.h @@ -0,0 +1,168 @@ +/**  + * @file llvoicechannel.h + * @brief Voice channel related classes + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, 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$ + */ + +#ifndef LL_VOICECHANNEL_H +#define LL_VOICECHANNEL_H + +#include "llhandle.h" +#include "llvoiceclient.h" + +class LLPanel; + +class LLVoiceChannel : public LLVoiceClientStatusObserver +{ +public: +	typedef enum e_voice_channel_state +	{ +		STATE_NO_CHANNEL_INFO, +		STATE_ERROR, +		STATE_HUNG_UP, +		STATE_READY, +		STATE_CALL_STARTED, +		STATE_RINGING, +		STATE_CONNECTED +	} EState; + +	LLVoiceChannel(const LLUUID& session_id, const std::string& session_name); +	virtual ~LLVoiceChannel(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + +	virtual void handleStatusChange(EStatusType status); +	virtual void handleError(EStatusType status); +	virtual void deactivate(); +	virtual void activate(); +	virtual void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	virtual void getChannelInfo(); +	virtual BOOL isActive(); +	virtual BOOL callStarted(); +	const std::string& getSessionName() const { return mSessionName; } + +	const LLUUID getSessionID() { return mSessionID; } +	EState getState() { return mState; } + +	void updateSessionID(const LLUUID& new_session_id); +	const LLSD& getNotifyArgs() { return mNotifyArgs; } + +	static LLVoiceChannel* getChannelByID(const LLUUID& session_id); +	static LLVoiceChannel* getChannelByURI(std::string uri); +	static LLVoiceChannel* getCurrentVoiceChannel() { return sCurrentVoiceChannel; } +	static void initClass(); +	 +	static void suspend(); +	static void resume(); + +protected: +	virtual void setState(EState state); +	void toggleCallWindowIfNeeded(EState state); +	void setURI(std::string uri); + +	std::string	mURI; +	std::string	mCredentials; +	LLUUID		mSessionID; +	EState		mState; +	std::string	mSessionName; +	LLSD mNotifyArgs; +	BOOL		mIgnoreNextSessionLeave; +	LLHandle<LLPanel> mLoginNotificationHandle; + +	typedef std::map<LLUUID, LLVoiceChannel*> voice_channel_map_t; +	static voice_channel_map_t sVoiceChannelMap; + +	typedef std::map<std::string, LLVoiceChannel*> voice_channel_map_uri_t; +	static voice_channel_map_uri_t sVoiceChannelURIMap; + +	static LLVoiceChannel* sCurrentVoiceChannel; +	static LLVoiceChannel* sSuspendedVoiceChannel; +	static BOOL sSuspended; +}; + +class LLVoiceChannelGroup : public LLVoiceChannel +{ +public: +	LLVoiceChannelGroup(const LLUUID& session_id, const std::string& session_name); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); +	/*vritual*/ void setChannelInfo( +		const std::string& uri, +		const std::string& credentials); +	/*virtual*/ void getChannelInfo(); + +protected: +	virtual void setState(EState state); + +private: +	U32 mRetries; +	BOOL mIsRetrying; +}; + +class LLVoiceChannelProximal : public LLVoiceChannel, public LLSingleton<LLVoiceChannelProximal> +{ +public: +	LLVoiceChannelProximal(); + +	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +	/*virtual*/ BOOL isActive(); +	/*virtual*/ void activate(); +	/*virtual*/ void deactivate(); + +}; + +class LLVoiceChannelP2P : public LLVoiceChannelGroup +{ +public: +	LLVoiceChannelP2P(const LLUUID& session_id, const std::string& session_name, const LLUUID& other_user_id); + +	/*virtual*/ void handleStatusChange(EStatusType status); +	/*virtual*/ void handleError(EStatusType status); +    /*virtual*/ void activate(); +	/*virtual*/ void getChannelInfo(); + +	void setSessionHandle(const std::string& handle, const std::string &inURI); + +protected: +	virtual void setState(EState state); + +private: +	std::string	mSessionHandle; +	LLUUID		mOtherUserID; +	BOOL		mReceivedCall; +}; + +#endif  // LL_VOICECHANNEL_H diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 02f63a848b..2834284a9b 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -57,13 +57,13 @@  #include "llagent.h"  #include "llcachename.h"  #include "llimview.h" // for LLIMMgr -#include "llimpanel.h" // for LLVoiceChannel  #include "llparcel.h"  #include "llviewerparcelmgr.h"  #include "llfirstuse.h"  #include "llviewerwindow.h"  #include "llviewercamera.h"  #include "llvoavatarself.h" +#include "llvoicechannel.h"  #include "llfloaterfriends.h"  //VIVOX, inorder to refresh communicate panel  #include "llfloaterchat.h"		// for LLFloaterChat::addChat() diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index 8f74ea29ac..a091028ec2 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -545,7 +545,7 @@ BOOL LLWearable::isDirty() const  				else  				{  					// image found in current image list but not saved image list -					return FALSE; +					return TRUE;  				}  			}  		} diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b46b766fc0..d3366cdcaa 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -144,6 +144,7 @@    <texture name="Info" file_name="icons/Info.png" preload="false" />    <texture name="Info_Small" file_name="icons/Info_Small.png" preload="false" />    <texture name="Info_Off" file_name="navbar/Info_Off.png" preload="false" /> +  <texture name="Info_Over" file_name="icons/Info_Over.png" preload="false" />    <texture name="Info_Press" file_name="navbar/Info_Press.png" preload="false" />    <texture name="Inspector_Background" file_name="windows/Inspector_Background.png" preload="false" /> diff --git a/indra/newview/skins/default/xui/en/floater_about_land.xml b/indra/newview/skins/default/xui/en/floater_about_land.xml index 072fafd06e..aa0b4094b4 100644 --- a/indra/newview/skins/default/xui/en/floater_about_land.xml +++ b/indra/newview/skins/default/xui/en/floater_about_land.xml @@ -28,7 +28,9 @@       follows="left|top|right|bottom"       height="400"       layout="topleft" +     font="SansSerifSmall"       left="1" +       tab_padding_right="5"       name="landtab"       tab_position="top"       top="20" diff --git a/indra/newview/skins/default/xui/en/floater_camera.xml b/indra/newview/skins/default/xui/en/floater_camera.xml index 520249c2a2..a713cc32a0 100644 --- a/indra/newview/skins/default/xui/en/floater_camera.xml +++ b/indra/newview/skins/default/xui/en/floater_camera.xml @@ -1,17 +1,17 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <floater   can_dock="true" - can_minimize="true" - can_close="true"  + can_minimize="false" + can_close="true"   center_horiz="true" - follows="top" - height="110" + follows="bottom" + height="152"   layout="topleft"   name="camera_floater"   help_topic="camera_floater"   save_rect="true"   save_visibility="true" - width="105"> + width="150">      <floater.string       name="rotate_tooltip">          Rotate Camera Around Focus @@ -25,69 +25,71 @@          Move Camera Up and Down, Left and Right      </floater.string>      <panel -     border="true" -     height="79" +     border="false" +     height="110"       layout="topleft" -     left="0" +     left="2"       top="0" -     mouse_opaque="false"  +     mouse_opaque="false"       name="controls" -     width="105"> -        <joystick_rotate -         follows="top|left" -         height="64" -         image_selected="cam_rotate_in.tga" -         image_unselected="cam_rotate_out.tga" -         layout="topleft" -         left="2" -         name="cam_rotate_stick" -         picture_style="true" -         quadrant="left" -         scale_image="false" -         sound_flags="3" -         tool_tip="Orbit camera around focus" -         top="15" -         width="64" /> +     width="148">          <joystick_track           follows="top|left" -         height="64" -         image_selected="cam_tracking_in.tga" -         image_unselected="cam_tracking_out.tga" +         height="78" +         image_selected="Cam_Tracking_In" +         image_unselected="Cam_Tracking_Out"           layout="topleft" -         left="2" +         left="45"           name="cam_track_stick"           picture_style="true"           quadrant="left"           scale_image="false"           sound_flags="3"           tool_tip="Move camera up and down, left and right" -         top="15" +         top="22"           visible="false" -         width="64" /> +         width="78" /> +         <!--TODO: replace with slider, + - images -->          <joystick_zoom           follows="top|left" -         height="64" -         image_unselected="cam_zoom_out.tga" +         height="78" +         image_unselected="ScrollThumb_Vert"           layout="topleft" -         left_delta="70" -         minus_image="cam_zoom_minus_in.tga" +         left="7" +         minus_image="ScrollThumb_Vert"           name="zoom"           picture_style="true" -         plus_image="cam_zoom_plus_in.tga" +         plus_image="ScrollThumb_Vert"           quadrant="left"           scale_image="false"           sound_flags="3"           tool_tip="Zoom camera toward focus" -         top_delta="0" -         width="16" /> +         top="22" +         width="20" /> +         <joystick_rotate +         follows="top|left" +         height="78" +         image_selected="Cam_Rotate_In" +         image_unselected="Cam_Rotate_Out" +         layout="topleft" +         left="45" +         name="cam_rotate_stick" +         picture_style="true" +         quadrant="left" +         scale_image="false" +         sound_flags="3" +         visible="true" +         tool_tip="Orbit camera around focus" +         top="22" +         width="78" />          <panel -         height="70" +         height="78"           layout="topleft" -         left="15" +         left="36"           name="camera_presets" -         top="15" +         top="30"           visible="false" -         width="75"> +         width="78">              <button               height="30"               image_selected="CameraPreset_Rear" @@ -127,7 +129,7 @@               name="front_view"               picture_style="true"               tool_tip="Front View" -             top_pad="2" +             top_pad="5"               width="30">                  <click_callback                   function="CameraPresets.ChangeView" @@ -151,21 +153,21 @@          </panel>      </panel>      <panel -     border="true" -     height="25" +     border="false" +     height="42"       layout="topleft" -     left="0" -     top_pad="1" +     left="2" +     top_pad="0"       name="buttons" -     width="105"> +     width="148">          <button           height="23"           label=""           layout="topleft" -         left="2" +         left="23"           is_toggle="true"           image_overlay="Cam_Orbit_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="orbit_btn"           tab_stop="false"           tool_tip="Orbit camera" @@ -179,7 +181,7 @@           left_pad="0"           is_toggle="true"           image_overlay="Cam_Pan_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="pan_btn"           tab_stop="false"           tool_tip="Pan camera" @@ -191,7 +193,7 @@           layout="topleft"           left_pad="0"           image_overlay="Cam_Avatar_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="avatarview_btn"           tab_stop="false"           tool_tip="See as avatar" @@ -204,12 +206,11 @@           left_pad="0"           is_toggle="true"           image_overlay="Cam_FreeCam_Off" -         image_selected="PushButton_Selected_Press"  +         image_selected="PushButton_Selected_Press"           name="freecamera_btn"           tab_stop="false"           tool_tip="View object"           width="25">          </button> -              </panel>  </floater> diff --git a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml index 0bd4b441c6..d24d1b7064 100644 --- a/indra/newview/skins/default/xui/en/floater_nearby_chat.xml +++ b/indra/newview/skins/default/xui/en/floater_nearby_chat.xml @@ -14,7 +14,7 @@   save_rect="true"   title="Nearby Chat"   save_visibility="true" - single_instance="true"  + single_instance="true"   width="320">              <chat_history               allow_html="true"  diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml index 5f70f09a34..69525d48d2 100644 --- a/indra/newview/skins/default/xui/en/floater_pay.xml +++ b/indra/newview/skins/default/xui/en/floater_pay.xml @@ -34,7 +34,7 @@       type="string"       length="1"       follows="left|top" -     font="SansSerif" +     font="SansSerifSmall"       height="16"       layout="topleft"       left_pad="7" @@ -44,6 +44,7 @@      </text>      <button       height="23" +     font="SansSerifSmall"         label="L$1"       label_selected="L$1"       layout="topleft" @@ -53,7 +54,8 @@       width="80" />      <button       height="23" -     label="L$5" +     label="L$1" +     font="SansSerif"         label_selected="L$5"       layout="topleft"       left_pad="15" @@ -62,6 +64,7 @@      <button       height="23"       label="L$10" +     font="SansSerifHuge"         label_selected="L$10"       layout="topleft"       left="25" diff --git a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml index 8cdafe110a..d2b8455eab 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_notecard.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_notecard.xml @@ -83,7 +83,7 @@          Loading...      </text_editor>      <button -     follows="left|bottom" +     follows="right|bottom"       height="22"       label="Save"       label_selected="Save" diff --git a/indra/newview/skins/default/xui/en/floater_report_abuse.xml b/indra/newview/skins/default/xui/en/floater_report_abuse.xml index abde4ba5fa..884532c7a3 100644 --- a/indra/newview/skins/default/xui/en/floater_report_abuse.xml +++ b/indra/newview/skins/default/xui/en/floater_report_abuse.xml @@ -14,19 +14,19 @@       allow_no_texture="true"       default_image_name="None"       follows="left|top" -     height="125" +     height="150"       layout="topleft" -     left="10" -     name="screenshot" -     top="23" -     width="160" /> +     left="60" +     name="" +     top="15" +     width="220" />      <check_box       height="15"       label="Use this screenshot"       layout="topleft" -     left_pad="5" +     left="8"       name="screen_check" -     top="120" +     top_pad="-12"       width="116" />      <text       type="string" @@ -38,8 +38,8 @@       layout="topleft"       left="10"       name="reporter_title" -     top="140" -     width="60"> +     top_pad="0" +     width="100">          Reporter:      </text>      <text @@ -48,24 +48,25 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="10" +     left_pad="5"       name="reporter_field"       top_delta="0" -     width="193"> -        Loremipsum Dolorsitamut +     use_ellipses="true" +     width="200"> +        Loremipsum Dolorsitamut Longnamez      </text>      <text       type="string"       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="sim_title" -     top_pad="5" -     width="60"> +     top_pad="2" +     width="100">          Region:      </text>      <text @@ -74,10 +75,11 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="2" +     left_pad="5"       name="sim_field"       top_delta="0" -     width="193"> +     use_ellipses="true" +     width="200">          Region Name      </text>      <text @@ -85,13 +87,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="pos_title" -     top_pad="5" -     width="50"> +     top_pad="2" +     width="100">          Position:      </text>      <text @@ -100,10 +102,10 @@       follows="left|top"       height="16"       layout="topleft" -     left_pad="12" +     left_pad="5"       name="pos_field"       top_delta="0" -     width="193"> +     width="200">          {128.1, 128.1, 15.4}      </text>   <text @@ -114,7 +116,7 @@       layout="topleft"       left="10"       name="select_object_label" -     top_pad="5" +     top_pad="2"       width="310">          Click the button, then the abusive object:      </text> @@ -133,13 +135,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="48"       name="object_name_label"       top_delta="0" -     width="60"> +     width="80">          Object:      </text>      <text @@ -151,7 +153,8 @@       left_pad="6"       name="object_name"       top_delta="0" -     width="157"> +     use_ellipses="true" +     width="185">          Consetetur Sadipscing      </text>      <text @@ -159,13 +162,13 @@       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="48"       name="owner_name_label"       top_pad="0" -     width="60"> +     width="80">          Owner:      </text>      <text @@ -177,8 +180,9 @@       left_pad="6"       name="owner_name"       top_delta="0" -     width="157"> -        Hendrerit Vulputate +     use_ellipses="true" +     width="185"> +        Hendrerit Vulputate Kamawashi Longname      </text>      <combo_box       height="23" @@ -349,8 +353,8 @@       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0" @@ -368,11 +372,10 @@       left_delta="0"       max_length="32"       name="abuser_name_edit" -     top_pad="2" +     top_pad="0"       width="195" />      <button       height="23" -     font="SansSerifSmall"       label="Choose"       layout="topleft"       left_pad="5" @@ -394,13 +397,13 @@       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left="10"       name="abuser_name_title2" -     top_pad="5" +     top_pad="2"       width="313">          Location of Abuse:      </text> @@ -413,19 +416,19 @@       left="10"       max_length="256"       name="abuse_location_edit" -     top_pad="2" +     top_pad="0"       width="313" />      <text       type="string"       length="1"       follows="left|top"       height="16" -     font.name="SansSerif"  +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0"       name="sum_title" -     top_pad="5" +     top_pad="2"       width="313">          Summary:      </text> @@ -438,14 +441,14 @@       left_delta="0"       max_length="64"       name="summary_edit" -     top_pad="2" +     top_pad="0"       width="313" />      <text       type="string"       length="1"       follows="left|top" -     height="16" -     font.name="SansSerif"  +     height="14" +     font.name="SansSerif"       font.style="BOLD"       layout="topleft"       left_delta="0" @@ -461,9 +464,9 @@       height="16"       layout="topleft"       name="bug_aviso" -     left_pad="0" +     left_pad="10"       width="200"> -        Please be as specific as possible. +        Please be as specific as possible      </text>      <text_editor       follows="left|top" @@ -479,16 +482,15 @@       type="string"       length="1"       follows="left|top" -     height="50" +     height="30"       layout="topleft"       left="10" -     font.name="SansSerif"  -     font.style="BOLD" +     font.name="SansSerifSmall"       name="incomplete_title" -     top_pad="5" +     top_pad="2"       word_wrap="true"       width="313"> -        Note: Incomplete reports won't be investigated. +        * Incomplete reports won't be investigated      </text>       <button       left="80" diff --git a/indra/newview/skins/default/xui/en/floater_test_textbox.xml b/indra/newview/skins/default/xui/en/floater_test_textbox.xml index 8305452c85..c33ab8aa70 100644 --- a/indra/newview/skins/default/xui/en/floater_test_textbox.xml +++ b/indra/newview/skins/default/xui/en/floater_test_textbox.xml @@ -114,16 +114,59 @@          Escaped greater than >      </text>      <text -     type="string" -     length="1" -     bottom="390" -     label="N" -     layout="topleft" -     left="10" -     name="floater_map_north" -     right="30" -     text_color="1 1 1 0.7" -     top="370"> -        N -    </text> +   type="string" +   length="1" +   bottom="390" +   label="N" +   layout="topleft" +   left="10" +   name="right_aligned_text" +   width="380" +   halign="right"  +   text_color="1 1 1 0.7" +   top_pad="10"> +    Right aligned text +  </text> +  <text + type="string" + length="1" + bottom="390" + label="N" + layout="topleft" + left="10" + name="centered_text" + width="380" + halign="center" + text_color="1 1 1 0.7" + top_pad="10"> +    Centered text +  </text> +  <text + type="string" + length="1" + bottom="390" + label="N" + layout="topleft" + left="10" + name="centered_text" + width="380" + halign="left" + text_color="1 1 1 0.7" + top_pad="10"> +    Left aligned text +  </text> +  <text +   type="string" +   length="1" +   bottom="390" +   label="N" +   layout="topleft" +   left="10" +   name="floater_map_north" +   right="30" +   text_color="1 1 1 0.7" +   top="370"> +    N +  </text> +  </floater> diff --git a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml index cc17e9dd4b..eedb4383bb 100644 --- a/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_friends_view_sort.xml @@ -23,9 +23,14 @@         parameter="sort_status" />    </menu_item_check>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Friends.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="FriendsListShowIcons" /> +  </menu_item_check>    <menu_item_call name="organize_offline" label="Organize Offline Friends">      <menu_item_call.on_click function="People.Friends.ViewSort.Action" userdata="organize_offline" />    </menu_item_call> diff --git a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml index f91a961388..c002cd078f 100644 --- a/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_nearby_view_sort.xml @@ -12,9 +12,14 @@      <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="sort_distance" />    </menu_item_call>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Nearby.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Nearby.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="NearbyListShowIcons" /> +  </menu_item_check>    <menu_item_separator layout="topleft" />    <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects">      <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> diff --git a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml index d09871cff3..cfd6dc78b6 100644 --- a/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml +++ b/indra/newview/skins/default/xui/en/menu_people_recent_view_sort.xml @@ -23,9 +23,14 @@         parameter="sort_name" />    </menu_item_check>    <menu_item_separator layout="topleft" /> -  <menu_item_call name="view_icons" label="View People Icons"> -    <menu_item_call.on_click function="People.Recent.ViewSort.Action" userdata="view_icons" /> -  </menu_item_call> +  <menu_item_check name="view_icons" label="View People Icons"> +    <menu_item_check.on_click +     function="People.Recent.ViewSort.Action" +     parameter="view_icons" /> +    <menu_item_check.on_check +     function="CheckControl" +     parameter="RecentListShowIcons" /> +  </menu_item_check>    <menu_item_separator layout="topleft" />    <menu_item_call name="show_blocked_list" label="Show Blocked Residents & Objects">      <menu_item_call.on_click function="SideTray.ShowPanel" userdata="panel_block_list_sidetray" /> diff --git a/indra/newview/skins/default/xui/en/menu_place_add_button.xml b/indra/newview/skins/default/xui/en/menu_place_add_button.xml new file mode 100644 index 0000000000..e3a39a1242 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_place_add_button.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<menu + layout="topleft" + left="0" + mouse_opaque="false" + name="menu_folder_gear" + visible="false"> +    <menu_item_call +     label="Add Folder" +     layout="topleft" +     name="add_folder"> +        <on_click +         function="Places.LandmarksGear.Add.Action" +         parameter="category" /> +        <on_enable +         function="Places.LandmarksGear.Enable" +         parameter="category" /> +    </menu_item_call> +    <menu_item_call +     label="Add Landmark" +     layout="topleft" +     name="add_landmark"> +        <on_click +         function="Places.LandmarksGear.Add.Action" +         parameter="add_landmark" /> +    </menu_item_call> +</menu> diff --git a/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml new file mode 100644 index 0000000000..8db745fab7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_adhoc_control_panel.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + name="panel_im_control_panel" + width="146" + height="215" + border="false"> +    <avatar_list +     color="DkGray2" +     follows="left|top|right|bottom" +     height="130" +     ignore_online_status="true" +     layout="topleft" +     left="3" +     name="speakers_list" +     opaque="false" +     top="10" +     width="140" /> +    <button +     name="call_btn" +     label="Call" +     width="90" +     height="20" /> +    <button +     name="end_call_btn" +     label="End Call" +     width="90" +     height="20"  +     visible="false"/> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml index 9767a673f6..15b6b2a00d 100644 --- a/indra/newview/skins/default/xui/en/panel_group_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_group_control_panel.xml @@ -7,12 +7,14 @@      <avatar_list       color="DkGray2"       follows="left|top|right|bottom" -     height="150" +     height="130" +     ignore_online_status="true"       layout="topleft"       left="3"       name="speakers_list" +     opaque="false"       top="10" -     width="140"/> +     width="140" />      <button       name="group_info_btn"       label="Group Info" @@ -24,4 +26,10 @@       label="Call"       width="90"       height="20" /> +    <button +     name="end_call_btn" +     label="End Call" +     width="90" +     height="20"  +     visible="false"/>  </panel> diff --git a/indra/newview/skins/default/xui/en/panel_group_roles.xml b/indra/newview/skins/default/xui/en/panel_group_roles.xml index 75ded4f249..af1919bd8f 100644 --- a/indra/newview/skins/default/xui/en/panel_group_roles.xml +++ b/indra/newview/skins/default/xui/en/panel_group_roles.xml @@ -486,7 +486,7 @@ things in this group. There's a broad variety of Abilities.          </panel>      </tab_container>      <panel -     height="170" +     height="190"       layout="topleft"       follows="left|top"       left="10" @@ -556,7 +556,7 @@ things in this group. There's a broad variety of Abilities.          </scroll_list>      </panel>      <panel -     height="215" +     height="252"       layout="topleft"       left_delta="0"       name="roles_footer" diff --git a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml index 7dc94d1141..dca52def49 100644 --- a/indra/newview/skins/default/xui/en/panel_im_control_panel.xml +++ b/indra/newview/skins/default/xui/en/panel_im_control_panel.xml @@ -1,7 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <panel name="panel_im_control_panel"         width="96" -       height="215" +       height="225"         border="false">    <avatar_icon name="avatar_icon" @@ -24,6 +24,13 @@            width="90"            height="20" /> +    <button +     height="20" +     label="End Call" +     name="end_call_btn" +     visible="false" +     width="90" /> +    <button name="share_btn"            label="Share"            width="90" diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml index c33f68eaf7..5293043ba7 100644 --- a/indra/newview/skins/default/xui/en/panel_landmarks.xml +++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml @@ -114,22 +114,10 @@           image_disabled="AddItem_Disabled"           layout="topleft"           left_pad="5" -         name="add_landmark_btn" +         name="add_btn"           picture_style="true"           tool_tip="Add new landmark"           width="18" /> -        <button -         follows="bottom|left" -         height="18" -         image_selected="AddItem_Press" -         image_unselected="AddItem_Off" -         image_disabled="AddItem_Disabled" -         layout="topleft" -         left_pad="5" -         name="add_folder_btn" -         picture_style="true" -         tool_tip="Add new folder" -         width="18" />          <dnd_button           follows="bottom|right"           height="18" diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml index 7b19ab1a1c..69089e0e26 100644 --- a/indra/newview/skins/default/xui/en/panel_people.xml +++ b/indra/newview/skins/default/xui/en/panel_people.xml @@ -49,11 +49,13 @@ background_visible="true"       height="500"       layout="topleft"       left="10" +       font="SansSerifBigBold"       name="tabs"       tab_min_width="70"       tab_height="30"       tab_position="top"       top_pad="10" +     halign="center"         width="313">          <panel           follows="all" diff --git a/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml new file mode 100644 index 0000000000..b21fbc1795 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_prim_media_controls.xml @@ -0,0 +1,594 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel +	follows="left|right|top|bottom" +	name="MediaControls" +	bg_alpha_color="1 1 1 0" +	height="160" +	layout="topleft" +	mouse_opaque="false" +	width="800"> +  <panel +	  name="media_region" +	  bottom="125" +	  follows="left|right|top|bottom" +	  layout="topleft" +	  left="20" +	  mouse_opaque="false" +	  right="-20" +	  top="20" /> +  <layout_stack +	  follows="left|right|bottom" +	  height="32" +	  layout="topleft" +	  animate="false" +	  left="0" +	  orientation="horizontal" +	  top="96"> +	<!-- outer layout_panels center the inner one --> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +	<panel +		name="media_progress_indicator" +		height="22" +		layout="topleft" +		left="0" +		top="0" +		auto_resize="false" +		user_resize="false" +		min_width="100" +		width="200"> +	  <progress_bar +		  name="media_progress_bar" +		  color_bar="1 1 1 0.96" +		  follows="left|right|top" +		  height="16" +		  layout="topleft" +		  left="0" +		  tool_tip="Media is Loading"/> +	</panel> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +  </layout_stack> +  <layout_stack +	  name="media_controls" +	  follows="left|right" +	  animate="false" +	  height="32" +	  layout="topleft" +	  left="0" +	  orientation="horizontal" +	  top="128"> +	<!-- outer layout_panels center the inner one --> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +	<layout_panel +		name="back" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="22" +		width="22" +		top="4"> +	  <button +		  auto_resize="false" +		  height="22" +		  image_selected="media_btn_back.png" +		  image_unselected="media_btn_back.png" +		  layout="topleft" +		  tool_tip="Step back" +		  picture_style="true" +		  width="22" +		  top_delta="4"> +		<button.commit_callback +			function="MediaCtrl.Back" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="fwd" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="10" +		min_width="17" +		width="17"> +	  <button +		  height="22" +		  image_selected="media_btn_forward.png" +		  image_unselected="media_btn_forward.png" +		  layout="topleft" +		  tool_tip="Step forward" +		  picture_style="true" +		  top_delta="0" +		  min_width="17" +		  width="17"> +		<button.commit_callback +			function="MediaCtrl.Forward" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="home" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="-2" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_home.png" +		  image_unselected="media_btn_home.png" +		  layout="topleft" +		  tool_tip="Home page" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Home" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="media_stop" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="2" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_stop.tga" +		  image_unselected="button_anim_stop.tga" +		  layout="topleft" +		  tool_tip="Stop media" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Stop" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="reload" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="6" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_reload.png" +		  image_unselected="media_btn_reload.png" +		  layout="topleft" +		  tool_tip="Reload" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Reload" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="stop" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="10" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_stoploading.png" +		  image_unselected="media_btn_stoploading.png" +		  layout="topleft" +		  picture_style="true" +		  tool_tip = "Stop loading" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Stop" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="play" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="14" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_play.tga" +		  image_unselected="button_anim_play.tga" +		  layout="topleft" +		  tool_tip = "Play media" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Play" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="pause" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		top="18" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="button_anim_pause.tga" +		  image_unselected="button_anim_pause.tga" +		  layout="topleft" +		  tool_tip = "Pause media" +		  picture_style="true"> +		<button.commit_callback +			function="MediaCtrl.Pause" /> +	  </button> +	</layout_panel> +	<!-- media URL entry  --> +	<layout_panel +		name="media_address" +		auto_resize="true" +		user_resize="false" +		height="22" +		follows="left|right|bottom" +		layout="topleft" +		width="190" +		min_width="90"> +	  <!-- +		  RE-ENABLE THIS WHEN WE HAVE A HISTORY DROP-DOWN AGAIN + +<combo_box +name="media_address_url" +allow_text_entry="true" +height="22" +layout="topleft" +max_chars="1024" +tool_tip = "Media URL" +<combo_box.commit_callback +function="MediaCtrl.CommitURL" /> +</combo_box> +	  --> +	  <line_editor  +		  name="media_address_url" +		  follows="left|right"  +		  height="22" +		  top="0" +		  tool_tip="Media URL" +		  text_pad_right="16">  +		<line_editor.commit_callback +			function="MediaCtrl.CommitURL"/> +	  </line_editor> +	  <layout_stack +		  animate="false" +		  follows="right" +		  width="32" +		  min_width="32" +		  height="16" +		  top="3" +		  orientation="horizontal" +		  left_pad="-38"> +		<icon +			name="media_whitelist_flag" +			follows="top|right" +			height="16" +			image_name="smicon_warn.tga" +			layout="topleft" +			tool_tip="White List enabled" +			min_width="16" +			width="16" /> +		<icon +			name="media_secure_lock_flag" +			height="16" +			image_name="inv_item_eyes.tga" +			layout="topleft" +			tool_tip="Secured Browsing" +			min_width="16" +			width="16" /> +	  </layout_stack> +	</layout_panel> +	<layout_panel +		name="media_play_position" +		auto_resize="true" +		user_resize="false" +		follows="left|right|top|bottom" +		layout="topleft" +		min_width="100" +		width="200"> +	  <slider_bar +		  name="media_play_slider" +		  follows="left|right|top" +		  height="22" +		  increment="0.05" +		  initial_value="0.5" +		  layout="topleft" +		  tool_tip="Movie play progress" +		  min_width="100" +		  width="200"> +		<slider_bar.commit_callback +			function="MediaCtrl.JumpProgress" /> +	  </slider_bar> +	</layout_panel> +	<layout_panel +		name="media_volume" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		height="24" +		min_width="24" +		width="24"> +	  <button +		  name="media_volume_button" +		  height="22" +		  image_selected="icn_speaker-muted_dark.tga" +		  image_unselected="icn_speaker_dark.tga" +		  is_toggle="true" +		  layout="topleft" +		  scale_image="false"  +		  picture_style="true" +		  tool_tip="Mute This Media" +		  top_delta="22" +		  min_width="24" +		  width="24" > +		<button.commit_callback +			function="MediaCtrl.ToggleMute" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="volume_up" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="20" +		height="14" +		width="20"> +	  <button +		  top="-3" +		  height="14" +		  image_selected="media_btn_scrollup.png" +		  image_unselected="media_btn_scrollup.png" +		  layout="topleft" +		  tool_tip="Volume up" +		  picture_style="true" +		  scale_image="true" +		  min_width="20" +		  width="20" > +		<button.commit_callback +			function="MediaCtrl.CommitVolumeUp" /> +	  </button> +	</layout_panel> +	<layout_panel +		name="volume_down" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="20" +		height="14" +		width="20"> +	  <button +		  top="-5" +		  height="14" +		  image_selected="media_btn_scrolldown.png" +		  image_unselected="media_btn_scrolldown.png" +		  layout="topleft" +		  tool_tip="Volume down" +		  picture_style="true" +		  scale_image="true" +		  min_width="20" +		  width="20"> +		<button.commit_callback +			function="MediaCtrl.CommitVolumeDown" /> +	  </button> +	</layout_panel> +	<!-- Scroll pad --> +	<layout_panel +		name="media_panel_scroll" +		auto_resize="false" +		user_resize="false" +		height="32" +		follows="left|right|top|bottom" +		layout="topleft" +		min_width="32" +		width="32"> +	  <icon +		  height="32" +		  image_name="media_panel_scrollbg.png" +		  layout="topleft" +		  top="0" +		  min_width="32" +		  width="32" /> +	  <button +		  name="scrollup" +		  height="8" +		  image_selected="media_btn_scrollup.png" +		  image_unselected="media_btn_scrollup.png" +		  layout="topleft" +		  tool_tip="Scroll up" +		  picture_style="true" +		  scale_image="false" +		  left="12" +		  top_delta="4" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrollleft" +		  height="8" +		  image_selected="media_btn_scrollleft.png" +		  image_unselected="media_btn_scrollleft.png" +		  layout="topleft" +		  left="3" +		  tool_tip="Scroll left" +		  picture_style="true" +		  scale_image="false" +		  top="12" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrollright" +		  height="8" +		  image_selected="media_btn_scrollright.png" +		  image_unselected="media_btn_scrollright.png" +		  layout="topleft" +		  left_pad="9" +		  tool_tip="Scroll right" +		  picture_style="true" +		  scale_image="false" +		  top_delta="0" +		  min_width="8" +		  width="8" /> +	  <button +		  name="scrolldown" +		  height="8" +		  image_selected="media_btn_scrolldown.png" +		  image_unselected="media_btn_scrolldown.png" +		  layout="topleft" +		  left="12" +		  tool_tip="Scroll down" +		  picture_style="true" +		  scale_image="false" +		  top="20" +		  min_width="8" +		  width="8" /> +	</layout_panel> +	<layout_panel +		name="zoom_frame" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		height="28" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_optimalzoom.png" +		  image_unselected="media_btn_optimalzoom.png" +		  layout="topleft" +		  tool_tip="Zoom" +		  picture_style="true" +		  min_width="22" +		  width="22"> +		<button.commit_callback +			function="MediaCtrl.Zoom" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="new_window" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="22" +		width="22"> +	  <button +		  height="22" +		  image_selected="media_btn_newwindow.png" +		  image_unselected="media_btn_newwindow.png" +		  layout="topleft" +		  tool_tip = "Open URL in browser" +		  picture_style="true" +		  top_delta="-3" +		  min_width="24" +		  width="24" > +		<button.commit_callback +			function="MediaCtrl.Open" /> +	  </button> +	</layout_panel> +<!-- +	<panel +		height="22" +		layout="topleft" +		auto_resize="false" +		min_width="3" +		width="3"> +	  <icon +		  height="22" +		  image_name="media_panel_divider.png" +		  layout="topleft" +		  top="0" +		  min_width="3" +		  width="3" /> +	</panel> +--> +	<layout_panel +		name="close" +		auto_resize="false" +		user_resize="false" +		layout="topleft" +		min_width="21" +		width="21" > +	  <button +		  height="22" +		  image_selected="media_btn_done.png" +		  image_unselected="media_btn_done.png" +		  layout="topleft" +		  tool_tip ="Close media control" +		  picture_style="true" +		  top_delta="-4" +		  width="21" > +		<button.commit_callback +			function="MediaCtrl.Close" /> +	  </button> +	</layout_panel> +	<layout_panel +		width="0" +		layout="topleft" +		user_resize="false" /> +  </layout_stack> +</panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 81bc12c33c..4eacd72a7d 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -61,9 +61,7 @@  	<string name="TooltipFlagGroupScripts">Group Scripts</string>  	<string name="TooltipFlagNoScripts">No Scripts</string>  	<string name="TooltipLand">Land:</string> -	<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>	 -	<string name="TooltipAltLeft">Alt+← for previous tab</string>	 -	<string name="TooltipAltRight">Alt+→ for next tab</string>	 +	<string name="TooltipMustSingleDrop">Only a single item can be dragged here</string>  	<!-- tooltips for Urls -->  	<string name="TooltipHttpUrl">Click to view this web page</string> @@ -264,10 +262,6 @@  	<string name="TrackYourCamera">Track your camera</string>  	<string name="ControlYourCamera">Control your camera</string> -	<!-- IM --> -	<string name="IM_logging_string">-- Instant message logging enabled --</string> -	<string name="Unnamed">(Unnamed)</string> -	  	<!-- Sim Access labels -->  	<string name="SIM_ACCESS_PG">PG</string>  	<string name="SIM_ACCESS_MATURE">Mature</string> @@ -2022,15 +2016,14 @@ this texture in your inventory  	<string name="IMTeen">teen</string>  	<!-- floater region info --> +	<!-- The following will replace variable [ALL_ESTATES] in notifications EstateAllowed*, EstateBanned*, EstateManager* -->  	<string name="RegionInfoError">error</string>  	<string name="RegionInfoAllEstatesOwnedBy"> -		all estates -owned by [OWNER] +		all estates owned by [OWNER]  	</string> -	<string name="RegionInfoAllEstatesYouOwn">all estates you owned</string> +	<string name="RegionInfoAllEstatesYouOwn">all estates that you own</string>  	<string name="RegionInfoAllEstatesYouManage"> -		all estates that -you managed for [OWNER] +		all estates that you manage for [OWNER]  	</string>  	<string name="RegionInfoAllowedResidents">Allowed residents: ([ALLOWEDAGENTS], max [MAXACCESS])</string>  	<string name="RegionInfoAllowedGroups">Allowed groups: ([ALLOWEDGROUPS], max [MAXACCESS])</string> @@ -2884,7 +2877,14 @@ If you continue to receive this message, contact the [SUPPORT_SITE].  	  Failed to start viewer  	</string> -  <!-- IM system messages --> +	<!-- IM system messages --> +	<string name="IM_logging_string">-- Instant message logging enabled --</string> +	<string name="IM_typing_start_string">[NAME] is typing...</string> +	<string name="Unnamed">(Unnamed)</string> +	<string name="IM_moderated_chat_label">(Moderated: Voices off by default)</string> +	<string name="IM_unavailable_text_label">Text chat is not available for this call.</string> + +    <string name="ringing-im">      Joining Voice Chat...    </string> diff --git a/indra/newview/skins/default/xui/en/widgets/chat_history.xml b/indra/newview/skins/default/xui/en/widgets/chat_history.xml index b72d59524e..ea6997ebd5 100644 --- a/indra/newview/skins/default/xui/en/widgets/chat_history.xml +++ b/indra/newview/skins/default/xui/en/widgets/chat_history.xml @@ -4,8 +4,8 @@      message_separator="panel_chat_separator.xml"      left_text_pad="10"  	right_text_pad="15" -    left_widget_pad="5" -	rigth_widget_pad="10" +    left_widget_pad="0" +	right_widget_pad="10"  	max_length="2147483647"  	enabled="false"  	track_bottom="true" diff --git a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml index 89e442baec..ab4ad94089 100644 --- a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml +++ b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml @@ -23,7 +23,8 @@                                image_selected="DropDown_Selected"                                image_disabled="DropDown_Disabled"                                image_disabled_selected="DropDown_Disabled_Selected" /> -  <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" /> +  <gesture_combo_box.combo_list bg_writeable_color="MenuDefaultBgColor" +                                scroll_bar_bg_visible="true" />    <gesture_combo_box.combo_editor name="Combo Text Entry"                            select_on_focus="true"                            font="SansSerifSmall" /> diff --git a/indra/newview/skins/default/xui/en/widgets/tab_container.xml b/indra/newview/skins/default/xui/en/widgets/tab_container.xml index 2fe5f517a2..7d10df1af7 100644 --- a/indra/newview/skins/default/xui/en/widgets/tab_container.xml +++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml @@ -1,6 +1,7 @@  <?xml version="1.0" encoding="utf-8" standalone="yes" ?>  <tab_container tab_min_width="60"                 tab_max_width="150" +               font_halign="left"                 tab_height="16">    <first_tab tab_top_image_unselected="TabTop_Left_Off"                 tab_top_image_selected="TabTop_Left_Selected"  | 
