From 3f0082a9dda60432b8b759e09f19b495d9d5275c Mon Sep 17 00:00:00 2001 From: Armin Weatherwax Date: Mon, 8 Jun 2009 11:10:27 +0200 Subject: Linux middle mouse button paste/primary selection support and gtk clipboard handler (fixes crashbug using synergy mouse-keyboard-clipboard-sharing over lan) modified: linden/doc/contributions.txt modified: linden/indra/llui/llclipboard.cpp modified: linden/indra/llui/llclipboard.h modified: linden/indra/llui/llfloater.cpp modified: linden/indra/llui/llfloater.h modified: linden/indra/llui/lllineeditor.cpp modified: linden/indra/llui/lllineeditor.h modified: linden/indra/llui/lltexteditor.cpp modified: linden/indra/llui/lltexteditor.h modified: linden/indra/llui/llview.cpp modified: linden/indra/llui/llview.h modified: linden/indra/llwindow/CMakeLists.txt new file: linden/indra/llwindow/llmousehandler.cpp modified: linden/indra/llwindow/llmousehandler.h modified: linden/indra/llwindow/llwindow.cpp modified: linden/indra/llwindow/llwindow.h modified: linden/indra/llwindow/llwindowsdl.cpp modified: linden/indra/llwindow/llwindowsdl.h modified: linden/indra/newview/lltool.cpp modified: linden/indra/newview/lltool.h modified: linden/indra/newview/llviewertexteditor.cpp modified: linden/indra/newview/llviewertexteditor.h modified: linden/indra/newview/llviewerwindow.cpp modified: linden/indra/newview/llviewerwindow.h (cherry picked from commit 594f4830922f4294dda432fa748935adffaeed8f) --- linden/doc/contributions.txt | 3 + linden/indra/llui/llclipboard.cpp | 41 ++ linden/indra/llui/llclipboard.h | 11 +- linden/indra/llui/llfloater.cpp | 6 + linden/indra/llui/llfloater.h | 2 +- linden/indra/llui/lllineeditor.cpp | 83 +++- linden/indra/llui/lllineeditor.h | 13 +- linden/indra/llui/lltexteditor.cpp | 91 ++++- linden/indra/llui/lltexteditor.h | 8 + linden/indra/llui/llview.cpp | 78 ++++ linden/indra/llui/llview.h | 4 + linden/indra/llwindow/CMakeLists.txt | 1 + linden/indra/llwindow/llmousehandler.cpp | 59 +++ linden/indra/llwindow/llmousehandler.h | 21 +- linden/indra/llwindow/llwindow.cpp | 16 + linden/indra/llwindow/llwindow.h | 6 + linden/indra/llwindow/llwindowsdl.cpp | 570 +++++----------------------- linden/indra/llwindow/llwindowsdl.h | 13 +- linden/indra/newview/lltool.cpp | 15 +- linden/indra/newview/lltool.h | 3 + linden/indra/newview/llviewertexteditor.cpp | 79 ++-- linden/indra/newview/llviewertexteditor.h | 2 + linden/indra/newview/llviewerwindow.cpp | 479 ++++++----------------- linden/indra/newview/llviewerwindow.h | 9 +- 24 files changed, 696 insertions(+), 917 deletions(-) create mode 100644 linden/indra/llwindow/llmousehandler.cpp diff --git a/linden/doc/contributions.txt b/linden/doc/contributions.txt index 9886640..a1c8624 100644 --- a/linden/doc/contributions.txt +++ b/linden/doc/contributions.txt @@ -61,11 +61,14 @@ Alissa Sabre VWR-7168 VWR-7087 VWR-7086 + VWR-9190 VWR-10728 Angus Boyd VWR-592 Argent Stonecutter VWR-68 +Armin Weatherwax + VWR-8436 Asuka Neely VWR-3434 Balp Allen diff --git a/linden/indra/llui/llclipboard.cpp b/linden/indra/llui/llclipboard.cpp index d5255e7..f33f3fa 100644 --- a/linden/indra/llui/llclipboard.cpp +++ b/linden/indra/llui/llclipboard.cpp @@ -92,3 +92,44 @@ BOOL LLClipboard::canPasteString() const { return LLView::getWindow()->isClipboardTextAvailable(); } + + +void LLClipboard::copyFromPrimarySubstring(const LLWString &src, S32 pos, S32 len, const LLUUID& source_id ) +{ + mSourceID = source_id; + mString = src.substr(pos, len); + LLView::getWindow()->copyTextToPrimary( mString ); +} + + +const LLWString& LLClipboard::getPastePrimaryWString( LLUUID* source_id ) +{ + if( mSourceID.notNull() ) + { + LLWString temp_string; + LLView::getWindow()->pasteTextFromPrimary(temp_string); + + if( temp_string != mString ) + { + mSourceID.setNull(); + mString = temp_string; + } + } + else + { + LLView::getWindow()->pasteTextFromPrimary(mString); + } + + if( source_id ) + { + *source_id = mSourceID; + } + + return mString; +} + + +BOOL LLClipboard::canPastePrimaryString() const +{ + return LLView::getWindow()->isPrimaryTextAvailable(); +} diff --git a/linden/indra/llui/llclipboard.h b/linden/indra/llui/llclipboard.h index 706ed2a..7117f84 100644 --- a/linden/indra/llui/llclipboard.h +++ b/linden/indra/llui/llclipboard.h @@ -43,10 +43,19 @@ public: LLClipboard(); ~LLClipboard(); + /* We support two flavors of clipboard. The default is the explicitly + copy-and-pasted clipboard. The second is the so-called 'primary' clipboard + which is implicitly copied upon selection on platforms which expect this + (i.e. X11/Linux). */ + void copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); BOOL canPasteString() const; const LLWString& getPasteWString(LLUUID* source_id = NULL); - + + void copyFromPrimarySubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); + BOOL canPastePrimaryString() const; + const LLWString& getPastePrimaryWString(LLUUID* source_id = NULL); + private: LLUUID mSourceID; LLWString mString; diff --git a/linden/indra/llui/llfloater.cpp b/linden/indra/llui/llfloater.cpp index 2924c29..efe49eb 100644 --- a/linden/indra/llui/llfloater.cpp +++ b/linden/indra/llui/llfloater.cpp @@ -1187,6 +1187,12 @@ BOOL LLFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) return was_minimized || LLPanel::handleRightMouseDown( x, y, mask ); } +BOOL LLFloater::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + bringToFront( x, y ); + return LLPanel::handleMiddleMouseDown( x, y, mask ); +} + // virtual BOOL LLFloater::handleDoubleClick(S32 x, S32 y, MASK mask) diff --git a/linden/indra/llui/llfloater.h b/linden/indra/llui/llfloater.h index a6fe3cc..37081c2 100644 --- a/linden/indra/llui/llfloater.h +++ b/linden/indra/llui/llfloater.h @@ -178,7 +178,7 @@ public: virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); - + virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); virtual void onOpen() {} diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp index 498ef26..f905774 100644 --- a/linden/indra/llui/lllineeditor.cpp +++ b/linden/indra/llui/lllineeditor.cpp @@ -493,6 +493,9 @@ BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask) // delay cursor flashing mKeystrokeTimer.reset(); + // take selection to 'primary' clipboard + updatePrimary(); + return TRUE; } @@ -575,6 +578,17 @@ BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) return TRUE; } +BOOL LLLineEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + // llinfos << "MiddleMouseDown" << llendl; + setFocus( TRUE ); + if( canPastePrimary() ) + { + setCursorAtLocalPos(x); + pastePrimary(); + } + return TRUE; +} BOOL LLLineEditor::handleHover(S32 x, S32 y, MASK mask) { @@ -669,6 +683,9 @@ BOOL LLLineEditor::handleMouseUp(S32 x, S32 y, MASK mask) { // delay cursor flashing mKeystrokeTimer.reset(); + + // take selection to 'primary' clipboard + updatePrimary(); } return handled; @@ -872,7 +889,12 @@ BOOL LLLineEditor::handleSelectionKey(KEY key, MASK mask) } } - + if(handled) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + return handled; } @@ -945,20 +967,42 @@ BOOL LLLineEditor::canPaste() const return !mReadOnly && gClipboard.canPasteString(); } - -// paste from clipboard void LLLineEditor::paste() { - if (canPaste()) + bool is_primary = false; + pasteHelper(is_primary); +} + +void LLLineEditor::pastePrimary() +{ + bool is_primary = true; + pasteHelper(is_primary); +} + +// paste from primary (is_primary==true) or clipboard (is_primary==false) +void LLLineEditor::pasteHelper(bool is_primary) +{ + bool can_paste_it; + if (is_primary) + can_paste_it = canPastePrimary(); + else + can_paste_it = canPaste(); + + if (can_paste_it) { - LLWString paste = gClipboard.getPasteWString(); + LLWString paste; + if (is_primary) + paste = gClipboard.getPastePrimaryWString(); + else + paste = gClipboard.getPasteWString(); + if (!paste.empty()) { // Prepare for possible rollback LLLineEditorRollback rollback(this); // Delete any selected characters - if (hasSelection()) + if ((!is_primary) && hasSelection()) { deleteSelection(); } @@ -994,7 +1038,7 @@ void LLLineEditor::paste() clean_string = clean_string.substr(0, wchars_that_fit); reportBadKeystroke(); } - + mText.insert(getCursor(), clean_string); setCursor( getCursor() + (S32)clean_string.length() ); deselect(); @@ -1015,7 +1059,30 @@ void LLLineEditor::paste() } } - +// copy selection to primary +void LLLineEditor::copyPrimary() +{ + if( canCopy() ) + { + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = abs( mSelectionStart - mSelectionEnd ); + gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); + } +} + +BOOL LLLineEditor::canPastePrimary() const +{ + return !mReadOnly && gClipboard.canPastePrimaryString(); +} + +void LLLineEditor::updatePrimary() +{ + if(canCopy() ) + { + copyPrimary(); + } +} + BOOL LLLineEditor::handleSpecialKey(KEY key, MASK mask) { BOOL handled = FALSE; diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h index 11cbcd9..b11f8b9 100644 --- a/linden/indra/llui/lllineeditor.h +++ b/linden/indra/llui/lllineeditor.h @@ -89,6 +89,7 @@ public: /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); + /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); /*virtual*/ void onMouseCaptureLost(); @@ -96,13 +97,16 @@ public: // LLEditMenuHandler overrides virtual void cut(); virtual BOOL canCut() const; - virtual void copy(); virtual BOOL canCopy() const; - virtual void paste(); virtual BOOL canPaste() const; - + + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; + virtual void doDelete(); virtual BOOL canDoDelete() const; @@ -219,6 +223,9 @@ public: private: // private helper methods + + void pasteHelper(bool is_primary); + void removeChar(); void addChar(const llwchar c); void setCursorAtLocalPos(S32 local_mouse_x); diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp index 3813e76..95cce60 100644 --- a/linden/indra/llui/lltexteditor.cpp +++ b/linden/indra/llui/lltexteditor.cpp @@ -1203,6 +1203,18 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) } +BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + setFocus( TRUE ); + if( canPastePrimary() ) + { + setCursorAtLocalPos( x, y, TRUE ); + pastePrimary(); + } + return TRUE; +} + + BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -1323,6 +1335,9 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) setCursorAtLocalPos( x, y, TRUE ); endSelection(); + + // take selection to primary clipboard + updatePrimary(); } if( !hasSelection() ) @@ -1330,6 +1345,9 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) handleMouseUpOverSegment( x, y, mask ); } + // take selection to 'primary' clipboard + updatePrimary(); + handled = TRUE; } @@ -1392,8 +1410,12 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) // delay cursor flashing resetKeystrokeTimer(); + // take selection to 'primary' clipboard + updatePrimary(); + handled = TRUE; } + return handled; } @@ -1689,6 +1711,12 @@ BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask) } } + if( handled ) + { + // take selection to 'primary' clipboard + updatePrimary(); + } + return handled; } @@ -1868,22 +1896,46 @@ BOOL LLTextEditor::canPaste() const return !mReadOnly && gClipboard.canPasteString(); } - // paste from clipboard void LLTextEditor::paste() { - if (!canPaste()) + bool is_primary = false; + pasteHelper(is_primary); +} + +// paste from primary +void LLTextEditor::pastePrimary() +{ + bool is_primary = true; + pasteHelper(is_primary); +} + +// paste from primary (itsprimary==true) or clipboard (itsprimary==false) +void LLTextEditor::pasteHelper(bool is_primary) +{ + bool can_paste_it; + if (is_primary) + can_paste_it = canPastePrimary(); + else + can_paste_it = canPaste(); + + if (!can_paste_it) { return; } LLUUID source_id; - LLWString paste = gClipboard.getPasteWString(&source_id); + LLWString paste; + if (is_primary) + paste = gClipboard.getPastePrimaryWString(&source_id); + else + paste = gClipboard.getPasteWString(&source_id); + if (paste.empty()) { return; } // Delete any selected characters (the paste replaces them) - if( hasSelection() ) + if( (!is_primary) && hasSelection() ) { deleteSelection(TRUE); } @@ -1917,6 +1969,32 @@ void LLTextEditor::paste() } + +// copy selection to primary +void LLTextEditor::copyPrimary() +{ + if( !canCopy() ) + { + return; + } + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = abs( mSelectionStart - mSelectionEnd ); + gClipboard.copyFromPrimarySubstring(mWText, left_pos, length, mSourceID); +} + +BOOL LLTextEditor::canPastePrimary() const +{ + return !mReadOnly && gClipboard.canPastePrimaryString(); +} + +void LLTextEditor::updatePrimary() +{ + if (canCopy()) + { + copyPrimary(); + } +} + BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) { BOOL handled = FALSE; @@ -1992,6 +2070,11 @@ BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask) } } + if (handled) + { + updatePrimary(); + } + return handled; } diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h index 643b7c3..0777e5f 100644 --- a/linden/indra/llui/lltexteditor.h +++ b/linden/indra/llui/lltexteditor.h @@ -82,6 +82,8 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); + virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); + virtual BOOL handleKeyHere(KEY key, MASK mask ); virtual BOOL handleUnicodeCharHere(llwchar uni_char); @@ -117,6 +119,10 @@ public: virtual BOOL canCopy() const; virtual void paste(); virtual BOOL canPaste() const; + virtual void updatePrimary(); + virtual void copyPrimary(); + virtual void pastePrimary(); + virtual BOOL canPastePrimary() const; virtual void doDelete(); virtual BOOL canDoDelete() const; virtual void selectAll(); @@ -425,6 +431,8 @@ private: // // Methods // + void pasteHelper(bool is_primary); + void updateSegments(); void pruneSegments(); diff --git a/linden/indra/llui/llview.cpp b/linden/indra/llui/llview.cpp index 9cdf481..78bf168 100644 --- a/linden/indra/llui/llview.cpp +++ b/linden/indra/llui/llview.cpp @@ -981,6 +981,30 @@ BOOL LLView::handleRightMouseUp(S32 x, S32 y, MASK mask) } return handled; } + +BOOL LLView::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + LLView* handled_view = childrenHandleMiddleMouseDown( x, y, mask ); + BOOL handled = (handled_view != NULL); + if( !handled && blockMouseEvent(x, y) ) + { + handled = TRUE; + handled_view = this; + } + + return handled; +} + +BOOL LLView::handleMiddleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleMiddleMouseUp( x, y, mask ) != NULL; + if( !handled && blockMouseEvent(x, y) ) + { + handled = TRUE; + } + return handled; +} + LLView* LLView::childrenHandleScrollWheel(S32 x, S32 y, S32 clicks) { @@ -1142,6 +1166,34 @@ LLView* LLView::childrenHandleRightMouseDown(S32 x, S32 y, MASK mask) return handled_view; } +LLView* LLView::childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + LLView* handled_view = NULL; + + if (getVisible() && getEnabled() ) + { + for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (viewp->pointInView(local_x, local_y) && + viewp->getVisible() && + viewp->getEnabled() && + viewp->handleMiddleMouseDown( local_x, local_y, mask )) + { + if (sDebugMouseHandling) + { + sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage; + } + handled_view = viewp; + break; + } + } + } + return handled_view; +} + LLView* LLView::childrenHandleDoubleClick(S32 x, S32 y, MASK mask) { LLView* handled_view = NULL; @@ -1227,6 +1279,32 @@ LLView* LLView::childrenHandleRightMouseUp(S32 x, S32 y, MASK mask) return handled_view; } +LLView* LLView::childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask) +{ + LLView* handled_view = NULL; + if( getVisible() && getEnabled() ) + { + for ( child_list_iter_t child_it = mChildList.begin(); child_it != mChildList.end(); ++child_it) + { + LLView* viewp = *child_it; + S32 local_x = x - viewp->getRect().mLeft; + S32 local_y = y - viewp->getRect().mBottom; + if (viewp->pointInView(local_x, local_y) && + viewp->getVisible() && + viewp->getEnabled() && + viewp->handleMiddleMouseUp( local_x, local_y, mask )) + { + if (sDebugMouseHandling) + { + sMouseHandlerMessage = std::string("->") + viewp->mName + sMouseHandlerMessage; + } + handled_view = viewp; + break; + } + } + } + return handled_view; +} void LLView::draw() { diff --git a/linden/indra/llui/llview.h b/linden/indra/llui/llview.h index 80dd348..da7f164 100644 --- a/linden/indra/llui/llview.h +++ b/linden/indra/llui/llview.h @@ -463,6 +463,8 @@ public: /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); @@ -596,6 +598,8 @@ protected: LLView* childrenHandleHover(S32 x, S32 y, MASK mask); LLView* childrenHandleMouseUp(S32 x, S32 y, MASK mask); LLView* childrenHandleMouseDown(S32 x, S32 y, MASK mask); + LLView* childrenHandleMiddleMouseUp(S32 x, S32 y, MASK mask); + LLView* childrenHandleMiddleMouseDown(S32 x, S32 y, MASK mask); LLView* childrenHandleDoubleClick(S32 x, S32 y, MASK mask); LLView* childrenHandleScrollWheel(S32 x, S32 y, S32 clicks); LLView* childrenHandleRightMouseDown(S32 x, S32 y, MASK mask); diff --git a/linden/indra/llwindow/CMakeLists.txt b/linden/indra/llwindow/CMakeLists.txt index 95e315f..afce0c0 100644 --- a/linden/indra/llwindow/CMakeLists.txt +++ b/linden/indra/llwindow/CMakeLists.txt @@ -46,6 +46,7 @@ set(llwindows_HEADER_FILES set(viewer_SOURCE_FILES llwindow.cpp + llmousehandler.cpp ) set(viewer_HEADER_FILES diff --git a/linden/indra/llwindow/llmousehandler.cpp b/linden/indra/llwindow/llmousehandler.cpp new file mode 100644 index 0000000..ae2f147 --- /dev/null +++ b/linden/indra/llwindow/llmousehandler.cpp @@ -0,0 +1,59 @@ +/** + * @file llmousehandler.cpp + * @brief LLMouseHandler class implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-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 "llmousehandler.h" + +//virtual +BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down) +{ + BOOL handled = FALSE; + if (down) + { + switch (clicktype) + { + case CLICK_LEFT: handled = handleMouseDown(x, y, mask); break; + case CLICK_RIGHT: handled = handleRightMouseDown(x, y, mask); break; + case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; + case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + } + } + else + { + switch (clicktype) + { + case CLICK_LEFT: handled = handleMouseUp(x, y, mask); break; + case CLICK_RIGHT: handled = handleRightMouseUp(x, y, mask); break; + case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; + case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + } + } + return handled; +} diff --git a/linden/indra/llwindow/llmousehandler.h b/linden/indra/llwindow/llmousehandler.h index dba1fc1..45f837b 100644 --- a/linden/indra/llwindow/llmousehandler.h +++ b/linden/indra/llwindow/llmousehandler.h @@ -32,9 +32,10 @@ #ifndef LL_MOUSEHANDLER_H #define LL_MOUSEHANDLER_H -#include "llstring.h" +#include "linden_common.h" +#include "llrect.h" -// Abstract interface. +// Mostly-abstract interface. // Intended for use via multiple inheritance. // A class may have as many interfaces as it likes, but never needs to inherit one more than once. @@ -48,13 +49,23 @@ public: SHOW_IF_NOT_BLOCKED, SHOW_ALWAYS, } EShowToolTip; + typedef enum { + CLICK_LEFT, + CLICK_MIDDLE, + CLICK_RIGHT, + CLICK_DOUBLELEFT + } EClickType; + virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktype, BOOL down); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) = 0; + virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) = 0; + + virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) = 0; virtual EShowToolTip getShowToolTip() { return SHOW_IF_NOT_BLOCKED; }; virtual const std::string& getName() const = 0; diff --git a/linden/indra/llwindow/llwindow.cpp b/linden/indra/llwindow/llwindow.cpp index 44908fb..b4c8ff0 100644 --- a/linden/indra/llwindow/llwindow.cpp +++ b/linden/indra/llwindow/llwindow.cpp @@ -307,6 +307,22 @@ void *LLWindow::getMediaWindow() return getPlatformWindow(); } +//virtual +BOOL LLWindow::isPrimaryTextAvailable() +{ + return FALSE; // no +} +//virtual +BOOL LLWindow::pasteTextFromPrimary(LLWString &dst) +{ + return FALSE; // fail +} +// virtual +BOOL LLWindow::copyTextToPrimary(const LLWString &src) +{ + return FALSE; // fail +} + // static std::string LLWindow::getFontListSans() { diff --git a/linden/indra/llwindow/llwindow.h b/linden/indra/llwindow/llwindow.h index ffc117f..821de2f 100644 --- a/linden/indra/llwindow/llwindow.h +++ b/linden/indra/llwindow/llwindow.h @@ -184,9 +184,15 @@ public: virtual void captureMouse() = 0; virtual void releaseMouse() = 0; virtual void setMouseClipping( BOOL b ) = 0; + virtual BOOL isClipboardTextAvailable() = 0; virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; virtual BOOL copyTextToClipboard(const LLWString &src) = 0; + + virtual BOOL isPrimaryTextAvailable(); + virtual BOOL pasteTextFromPrimary(LLWString &dst); + virtual BOOL copyTextToPrimary(const LLWString &src); + virtual void flashIcon(F32 seconds) = 0; virtual F32 getGamma() = 0; virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma diff --git a/linden/indra/llwindow/llwindowsdl.cpp b/linden/indra/llwindow/llwindowsdl.cpp index 8111aaf..5209e6f 100644 --- a/linden/indra/llwindow/llwindowsdl.cpp +++ b/linden/indra/llwindow/llwindowsdl.cpp @@ -188,11 +188,12 @@ Display* LLWindowSDL::get_SDL_Display(void) LLWindowSDL::LLWindowSDL(const std::string& title, 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(fullscreen, flags), mGamma(1.0f) + S32 height, U32 flags, + BOOL fullscreen, BOOL clearBg, + BOOL disable_vsync, BOOL use_gl, + BOOL ignore_pixel_depth, U32 fsaa_samples) + : LLWindow(fullscreen, flags), Lock_Display(NULL), + Unlock_Display(NULL), mGamma(1.0f) { // Initialize the keyboard gKeyboard = new LLKeyboardSDL(); @@ -717,9 +718,33 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B #endif #if LL_X11 - init_x11clipboard(); + /* Grab the window manager specific information */ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if ( SDL_GetWMInfo(&info) ) + { + /* Save the information for later use */ + if ( info.subsystem == SDL_SYSWM_X11 ) + { + mSDL_Display = info.info.x11.display; + mSDL_XWindowID = info.info.x11.wmwindow; + Lock_Display = info.info.x11.lock_func; + Unlock_Display = info.info.x11.unlock_func; + } + else + { + llwarns << "We're not running under X11? Wild." + << llendl; + } + } + else + { + llwarns << "We're not running under any known WM. Wild." + << llendl; + } #endif // LL_X11 + //make sure multisampling is disabled by default glDisable(GL_MULTISAMPLE_ARB); @@ -763,8 +788,12 @@ BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL void LLWindowSDL::destroyContext() { llinfos << "destroyContext begins" << llendl; + #if LL_X11 - quit_x11clipboard(); + mSDL_Display = NULL; + mSDL_XWindowID = None; + Lock_Display = NULL; + Unlock_Display = NULL; #endif // LL_X11 // Clean up remaining GL state before blowing away window @@ -1212,523 +1241,125 @@ void LLWindowSDL::flashIcon(F32 seconds) #endif // LL_X11 } -#if LL_X11 -/* Lots of low-level X11 stuff to handle X11 copy-and-paste */ - -/* Our X11 clipboard support is a bit bizarre in various - organically-grown ways. Ideally it should be fixed to do - real string-type negotiation (this would make pasting to - xterm faster and pasting to UTF-8 emacs work properly), but - right now it has the rare and desirable trait of being - generally stable and working. */ - -typedef Atom x11clipboard_type; - -/* PRIMARY and CLIPBOARD are the two main kinds of - X11 clipboard. A third are the CUT_BUFFERs which an - obsolete holdover from X10 days and use a quite orthogonal - mechanism. CLIPBOARD is the type whose design most - closely matches SL's own win32-alike explicit copy-and-paste - paradigm. - - Pragmatically we support all three to varying degrees. When - we paste into SL, it is strictly from CLIPBOARD. When we copy, - we support (to as full an extent as the clipboard content type - allows) CLIPBOARD, PRIMARY, and CUT_BUFFER0. - */ -static x11clipboard_type get_x11_readwrite_clipboard_type(void) -{ - return XInternAtom(LLWindowSDL::get_SDL_Display(), "CLIPBOARD", False); -} - -static x11clipboard_type get_x11_write_clipboard_type(void) -{ - return XA_PRIMARY; -} - -/* This is where our own private cutbuffer goes - we don't use - a regular cutbuffer (XA_CUT_BUFFER0 etc) for intermediate - storage because their use isn't really defined for holding UTF8. */ -static x11clipboard_type get_x11_cutbuffer_clipboard_type(void) -{ - return XInternAtom(LLWindowSDL::get_SDL_Display(), "SECONDLIFE_CUTBUFFER", False); -} - -/* Some X11 atom-generators */ -static Atom get_x11_targets_atom(void) -{ - return XInternAtom(LLWindowSDL::get_SDL_Display(), "TARGETS", False); -} - -static Atom get_x11_text_atom(void) -{ - return XInternAtom(LLWindowSDL::get_SDL_Display(), "TEXT", False); -} - -/* These defines, and convert_data/convert_x11clipboard, - mostly exist to support non-text or unusually-encoded - clipboard data, which we don't really have a need for at - the moment. */ -#define SDLCLIPTYPE(A, B, C, D) (int)(((A)<<24)|((B)<<16)|((C)<<8)|((D)<<0)) -#define FORMAT_PREFIX "SECONDLIFE_x11clipboard_0x" - -static -x11clipboard_type convert_format(int type) +#if LL_GTK +BOOL LLWindowSDL::isClipboardTextAvailable() { - if (!gWindowImplementation) + if (ll_try_gtk_init()) { - llwarns << "!gWindowImplementation in convert_format()" - << llendl; - return XA_STRING; - } - - switch (type) - { - case SDLCLIPTYPE('T', 'E', 'X', 'T'): - // old-style X11 clipboard, strictly only ISO 8859-1 encoding - return XA_STRING; - case SDLCLIPTYPE('U', 'T', 'F', '8'): - // newer de-facto UTF8 clipboard atom - return XInternAtom(gWindowImplementation->mSDL_Display, - "UTF8_STRING", False); - default: - { - /* completely arbitrary clipboard types... we don't actually use - these right now, and support is skeletal. */ - char format[sizeof(FORMAT_PREFIX)+8+1]; /* Flawfinder: ignore */ - - snprintf(format, sizeof(format), "%s%08lx", FORMAT_PREFIX, (unsigned long)type); - return XInternAtom(gWindowImplementation->mSDL_Display, - format, False); + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + return gtk_clipboard_wait_is_text_available(clipboard) ? + TRUE : FALSE; } - } + return FALSE; // failure } -/* convert platform string to x11 clipboard format. for our - purposes this is pretty trivial right now. */ -static int -convert_data(int type, char *dst, const char *src, int srclen) +BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &text) { - int dstlen; - - dstlen = 0; - switch (type) + if (ll_try_gtk_init()) { - case SDLCLIPTYPE('T', 'E', 'X', 'T'): - case SDLCLIPTYPE('U', 'T', 'F', '8'): - if (src == NULL) - { - break; - } - if ( srclen == 0 ) - srclen = strlen(src); /* Flawfinder: ignore */ - - dstlen = srclen + 1; - - if ( dst ) // assume caller made it big enough by asking us + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + gchar * const data = gtk_clipboard_wait_for_text(clipboard); + if (data) { - memcpy(dst, src, srclen); /* Flawfinder: ignore */ - dst[srclen] = '\0'; + text = LLWString(utf8str_to_wstring(data)); + g_free(data); + return TRUE; } - break; - - default: - llwarns << "convert_data: Unknown medium type" << llendl; - break; } - return(dstlen); + return FALSE; // failure } -/* Convert x11clipboard data to platform string. This too is - pretty trivial for our needs right now, and just about identical - to above. */ -static int -convert_x11clipboard(int type, char *dst, const char *src, int srclen) +BOOL LLWindowSDL::copyTextToClipboard(const LLWString &text) { - int dstlen; - - dstlen = 0; - switch (type) + if (ll_try_gtk_init()) { - case SDLCLIPTYPE('U', 'T', 'F', '8'): - case SDLCLIPTYPE('T', 'E', 'X', 'T'): - if (src == NULL) - { - break; - } - if ( srclen == 0 ) - srclen = strlen(src); /* Flawfinder: ignore */ - - dstlen = srclen + 1; - - if ( dst ) // assume caller made it big enough by asking us - { - memcpy(dst, src, srclen); /* Flawfinder: ignore */ - dst[srclen] = '\0'; - } - break; - - default: - llwarns << "convert_x11clipboard: Unknown medium type" << llendl; - break; + const std::string utf8 = wstring_to_utf8str(text); + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); + return TRUE; } - return dstlen; -} - -int -LLWindowSDL::is_empty_x11clipboard(void) -{ - int retval; - - maybe_lock_display(); - retval = ( XGetSelectionOwner(mSDL_Display, get_x11_readwrite_clipboard_type()) == None ); - maybe_unlock_display(); - - return(retval); + return FALSE; // failure } -void -LLWindowSDL::put_x11clipboard(int type, int srclen, const char *src) +BOOL LLWindowSDL::isPrimaryTextAvailable() { - x11clipboard_type format; - int dstlen; - char *dst; - - format = convert_format(type); - dstlen = convert_data(type, NULL, src, srclen); - - dst = (char *)malloc(dstlen); - if ( dst != NULL ) + if (ll_try_gtk_init()) { - maybe_lock_display(); - Window root = DefaultRootWindow(mSDL_Display); - convert_data(type, dst, src, srclen); - // Cutbuffers are only allowed to have STRING atom types, - // but Emacs puts UTF8 inside them anyway. We cautiously - // don't. - if (type == SDLCLIPTYPE('T','E','X','T')) - { - // dstlen-1 so we don't include the trailing \0 - llinfos << "X11: Populating cutbuffer." <event.xevent; - - if ( (xevent.type == SelectionNotify)&& - (xevent.xselection.requestor == owner) ) - selection_response = 1; - } - } else { - llinfos << "X11: Waiting for SYSWM event..." << llendl; - } - } - llinfos << "X11: Clipboard arrived." <type != SDL_SYSWMEVENT ) - { - return(1); - } - - /* Handle window-manager specific clipboard events */ - switch (event->syswm.msg->event.xevent.type) { - /* Copy the selection from SECONDLIFE_CUTBUFFER to the requested property */ - case SelectionRequest: { - XSelectionRequestEvent *req; - XEvent sevent; - int seln_format; - unsigned long nbytes; - unsigned long overflow; - unsigned char *seln_data; - - req = &event->syswm.msg->event.xevent.xselectionrequest; - sevent.xselection.type = SelectionNotify; - sevent.xselection.display = req->display; - sevent.xselection.selection = req->selection; - sevent.xselection.target = None; - sevent.xselection.property = None; - sevent.xselection.requestor = req->requestor; - sevent.xselection.time = req->time; - if ( XGetWindowProperty(LLWindowSDL::get_SDL_Display(), DefaultRootWindow(LLWindowSDL::get_SDL_Display()), - get_x11_cutbuffer_clipboard_type(), 0, INT_MAX/4, False, req->target, - &sevent.xselection.target, &seln_format, - &nbytes, &overflow, &seln_data) == Success ) + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_SELECTION_PRIMARY); + gchar * const data = gtk_clipboard_wait_for_text(clipboard); + if (data) { - if ( sevent.xselection.target == req->target) - { - if ( sevent.xselection.target == XA_STRING || - sevent.xselection.target == - convert_format(SDLCLIPTYPE('U','T','F','8')) ) - { - if ( seln_data[nbytes-1] == '\0' ) - --nbytes; - } - XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor, req->property, - req->target, seln_format, PropModeReplace, - seln_data, nbytes); - sevent.xselection.property = req->property; - } else if (get_x11_targets_atom() == req->target) { - /* only advertise what we currently support */ - const int num_supported = 3; - Atom supported[num_supported] = { - XA_STRING, // will be over-written below - get_x11_text_atom(), - get_x11_targets_atom() - }; - supported[0] = sevent.xselection.target; - XChangeProperty(LLWindowSDL::get_SDL_Display(), req->requestor, - req->property, XA_ATOM, 32, PropModeReplace, - (unsigned char*)supported, - num_supported); - sevent.xselection.property = req->property; - llinfos << "Clipboard: An app asked us what selections format we offer." << llendl; - } else { - llinfos << "Clipboard: An app requested an unsupported selection format " << req->target << ", we have " << sevent.xselection.target << llendl; - sevent.xselection.target = None; - } - XFree(seln_data); + text = LLWString(utf8str_to_wstring(data)); + g_free(data); + return TRUE; } - int sendret = - XSendEvent(LLWindowSDL::get_SDL_Display(),req->requestor,False,0,&sevent); - if ((sendret==BadValue) || (sendret==BadWindow)) - llwarns << "Clipboard SendEvent failed" << llendl; - XSync(LLWindowSDL::get_SDL_Display(), False); - } - break; } - - /* Post the event for X11 clipboard reading above */ - return(1); + return FALSE; // failure } -int -LLWindowSDL::init_x11clipboard(void) +BOOL LLWindowSDL::copyTextToPrimary(const LLWString &text) { - SDL_SysWMinfo info; - int retval; - - /* Grab the window manager specific information */ - retval = -1; - SDL_SetError("SDL is not running on known window manager"); - - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&info) ) + if (ll_try_gtk_init()) { - /* Save the information for later use */ - if ( info.subsystem == SDL_SYSWM_X11 ) - { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.wmwindow; - Lock_Display = info.info.x11.lock_func; - Unlock_Display = info.info.x11.unlock_func; - - /* Enable the special window hook events */ - SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); - SDL_SetEventFilter(clipboard_filter_callback); - - retval = 0; - } - else - { - SDL_SetError("SDL is not running on X11"); - } + const std::string utf8 = wstring_to_utf8str(text); + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_SELECTION_PRIMARY); + gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); + return TRUE; } - return(retval); -} - -void -LLWindowSDL::quit_x11clipboard(void) -{ - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; - - SDL_SetEventFilter(NULL); // Stop custom event filtering + return FALSE; // failure } -/************************************************/ - +#else + BOOL LLWindowSDL::isClipboardTextAvailable() { - return !is_empty_x11clipboard(); + return FALSE; // unsupported } - + BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst) { - int cliplen; // seems 1 or 2 bytes longer than expected - char *cliptext = NULL; - get_x11clipboard(SDLCLIPTYPE('U','T','F','8'), &cliplen, &cliptext); - if (cliptext) - { - llinfos << "X11: Got UTF8 clipboard text." << llendl; - // at some future time we can use cliplen instead of relying on \0, - // if we ever grok non-ascii, non-utf8 encodings on the clipboard. - std::string clip_str(cliptext); - // we can't necessarily trust the incoming text to be valid UTF-8, - // but utf8str_to_wstring() seems to do an appropriate level of - // validation for avoiding over-reads. - dst = utf8str_to_wstring(clip_str); - /*llinfos << "X11 pasteTextFromClipboard: cliplen=" << cliplen << - " strlen(cliptext)=" << strlen(cliptext) << - " clip_str.length()=" << clip_str.length() << - " dst.length()=" << dst.length() << - llendl;*/ - free(cliptext); - return TRUE; // success - } - get_x11clipboard(SDLCLIPTYPE('T','E','X','T'), &cliplen, &cliptext); - if (cliptext) - { - llinfos << "X11: Got ISO 8859-1 clipboard text." << llendl; - std::string clip_str(cliptext); - std::string utf8_str = rawstr_to_utf8(clip_str); - dst = utf8str_to_wstring(utf8_str); - free(cliptext); - } - return FALSE; // failure + return FALSE; // unsupported } + BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s) { - std::string utf8text = wstring_to_utf8str(s); - const char* cstr = utf8text.c_str(); - if (cstr == NULL) - { - return FALSE; - } - int cstrlen = strlen(cstr); /* Flawfinder: ignore */ - int i; - for (i=0; igetDocPos() == mScrollbar->getDocPosMax()); - if (mOnScrollEndCallback && was_scrolled_to_bottom) - { - mOnScrollEndCallback(mOnScrollEndData); - } - - if( !handled && mTakesNonScrollClicks) - { - if( mIsSelecting ) - { - // Finish selection - if( y > getTextRect().mTop ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() - 1 ); - } - else - if( y < getTextRect().mBottom ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() + 1 ); - } - - setCursorAtLocalPos( x, y, TRUE ); - endSelection(); - - updateScrollFromCursor(); - } - - if( !hasSelection() ) - { - handleMouseUpOverSegment( x, y, mask ); - } - - handled = TRUE; - } - - // Delay cursor flashing - resetKeystrokeTimer(); + BOOL handled = FALSE; - if( hasMouseCapture() ) + if( hasMouseCapture() ) { if (mDragItem) { @@ -956,8 +914,15 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) } } mDragItem = NULL; - gFocusMgr.setMouseCapture( NULL ); - handled = TRUE; + } + + handled = LLTextEditor::handleMouseUp(x,y,mask); + + // Used to enable I Agree checkbox if the user scrolled through entire text + BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()); + if (mOnScrollEndCallback && was_scrolled_to_bottom) + { + mOnScrollEndCallback(mOnScrollEndData); } return handled; @@ -999,6 +964,24 @@ BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) return handled; } +BOOL LLViewerTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + handled = childrenHandleMiddleMouseDown(x, y, mask) != NULL; + if (!handled) + { + handled = LLTextEditor::handleMiddleMouseDown(x, y, mask); + } + return handled; +} + +BOOL LLViewerTextEditor::handleMiddleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleMiddleMouseUp(x, y, mask) != NULL; + + return handled; +} + BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -1021,7 +1004,6 @@ BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) } } } - setCursorAtLocalPos( x, y, FALSE ); deselect(); @@ -1059,6 +1041,9 @@ BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) // delay cursor flashing resetKeystrokeTimer(); + // take selection to 'primary' clipboard + updatePrimary(); + handled = TRUE; } return handled; diff --git a/linden/indra/newview/llviewertexteditor.h b/linden/indra/newview/llviewertexteditor.h index 4cd5850..062808a 100644 --- a/linden/indra/newview/llviewertexteditor.h +++ b/linden/indra/newview/llviewertexteditor.h @@ -58,6 +58,8 @@ public: // mousehandler overrides virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); diff --git a/linden/indra/newview/llviewerwindow.cpp b/linden/indra/newview/llviewerwindow.cpp index 7e6c24f..3b23bb9 100644 --- a/linden/indra/newview/llviewerwindow.cpp +++ b/linden/indra/newview/llviewerwindow.cpp @@ -547,19 +547,42 @@ bool LLViewerWindow::shouldShowToolTipFor(LLMouseHandler *mh) return false; } -BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) +BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down) { + std::string buttonname; + std::string buttonstatestr; + BOOL handled = FALSE; S32 x = pos.mX; S32 y = pos.mY; x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); - LLView::sMouseHandlerMessage.clear(); - - if (gDebugClicks) + if (down) + buttonstatestr = "down" ; + else + buttonstatestr = "up" ; + + switch (clicktype) { - llinfos << "ViewerWindow left mouse down at " << x << "," << y << llendl; + case LLMouseHandler::CLICK_LEFT: + mLeftMouseDown = down; + buttonname = "Left"; + break; + case LLMouseHandler::CLICK_RIGHT: + mRightMouseDown = down; + buttonname = "Right"; + break; + case LLMouseHandler::CLICK_MIDDLE: + mMiddleMouseDown = down; + buttonname = "Middle"; + break; + case LLMouseHandler::CLICK_DOUBLELEFT: + mLeftMouseDown = down; + buttonname = "Left Double Click"; + break; } + + LLView::sMouseHandlerMessage.clear(); if (gMenuBarView) { @@ -567,7 +590,10 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask gMenuBarView->resetMenuTrigger(); } - mLeftMouseDown = TRUE; + if (gDebugClicks) + { + llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl; + } // Make sure we get a coresponding mouseup event, even if the mouse leaves the window mWindow->captureMouse(); @@ -576,9 +602,9 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask gMouseIdleTimer.reset(); // Hide tooltips on mousedown - mToolTipBlocked = TRUE; + mToolTipBlocked = down; - // Also hide hover info on mousedown + // Also hide hover info on mousedown/mouseup if (gHoverView) { gHoverView->cancelHover(); @@ -587,7 +613,7 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask // Don't let the user move the mouse out of the window until mouse up. if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() ) { - mWindow->setMouseClipping(TRUE); + mWindow->setMouseClipping(down); } LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); @@ -598,10 +624,9 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); if (LLView::sDebugMouseHandling) { - llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl; + llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl; } - - return mouse_captor->handleMouseDown(local_x, local_y, mask); + return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down); } // Topmost view gets a chance before the hierarchy @@ -610,215 +635,95 @@ BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask { S32 local_x, local_y; top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) + if (down) { - return top_ctrl->handleMouseDown(local_x, local_y, mask); - } - else - { - gFocusMgr.setTopCtrl(NULL); + if (top_ctrl->pointInView(local_x, local_y)) + { + return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ; + } + else + { + gFocusMgr.setTopCtrl(NULL); + } } - } + else + handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask); + + } // Give the UI views a chance to process the click - if( mRootView->handleMouseDown(x, y, mask) ) + if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) ) { if (LLView::sDebugMouseHandling) { - llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl; + llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl; } return TRUE; } else if (LLView::sDebugMouseHandling) { - llinfos << "Left Mouse Down not handled by view" << llendl; - } - - if (gDisconnected) - { - return FALSE; - } - - if(LLToolMgr::getInstance()->getCurrentTool()->handleMouseDown( x, y, mask ) ) - { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - gFocusMgr.setKeyboardFocus(NULL); - return TRUE; - } - - return FALSE; -} - -BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) -{ - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage.clear(); - - if (gDebugClicks) - { - llinfos << "ViewerWindow left mouse double-click at " << x << "," << y << llendl; + llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl; } - - mLeftMouseDown = TRUE; - - // Hide tooltips - if( mToolTip ) + if (down) { - mToolTip->setVisible( FALSE ); - } - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - if (LLView::sDebugMouseHandling) + if (gDisconnected) { - llinfos << "Left Mouse Down handled by captor " << mouse_captor->getName() << llendl; - } - - return mouse_captor->handleDoubleClick(local_x, local_y, mask); - } - - // Check for hit on UI. - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) - { - return top_ctrl->handleDoubleClick(local_x, local_y, mask); + return FALSE; } - else + + if(LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) ) { - gFocusMgr.setTopCtrl(NULL); + // This is necessary to force clicks in the world to cause edit + // boxes that might have keyboard focus to relinquish it, and hence + // cause a commit to update their value. JC + gFocusMgr.setKeyboardFocus(NULL); + return TRUE; } } - - if (mRootView->handleDoubleClick(x, y, mask)) + else { - if (LLView::sDebugMouseHandling) + + mWindow->releaseMouse(); + + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + if( !handled ) { - llinfos << "Left Mouse Down" << LLView::sMouseHandlerMessage << llendl; + handled = mRootView->handleAnyMouseClick(x, y, mask, clicktype, down); + } + + + + if( !handled ) + { + if (tool) + { + handled = tool->handleAnyMouseClick(x, y, mask, clicktype, down); + } } - return TRUE; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Left Mouse Down not handled by view" << llendl; } - // Why is this here? JC 9/3/2002 - if (gNoRender) - { - return TRUE; - } + return (!down); +} - if(LLToolMgr::getInstance()->getCurrentTool()->handleDoubleClick( x, y, mask ) ) - { - return TRUE; - } +BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) +{ + BOOL down = TRUE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); +} - // if we got this far and nothing handled a double click, pass a normal mouse down - return handleMouseDown(window, pos, mask); +BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask) +{ + // try handling as a double-click first, then a single-click if that + // wasn't handled. + BOOL down = TRUE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_DOUBLELEFT,down) || + handleMouseDown(window, pos, mask); } BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage.clear(); - - if (gDebugClicks) - { - llinfos << "ViewerWindow left mouse up" << llendl; - } - - mLeftMouseDown = FALSE; - - // Indicate mouse was active - gMouseIdleTimer.reset(); - - // Hide tooltips on mouseup - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mouseup - if (gHoverView) gHoverView->cancelHover(); - - BOOL handled = FALSE; - - mWindow->releaseMouse(); - - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - - if( tool->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(FALSE); - } - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - if (LLView::sDebugMouseHandling) - { - llinfos << "Left Mouse Up handled by captor " << mouse_captor->getName() << llendl; - } - - return mouse_captor->handleMouseUp(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleMouseUp(local_x, local_y, mask); - } - - if( !handled ) - { - handled = mRootView->handleMouseUp(x, y, mask); - } - - if (LLView::sDebugMouseHandling) - { - if (handled) - { - llinfos << "Left Mouse Up" << LLView::sMouseHandlerMessage << llendl; - } - else - { - llinfos << "Left Mouse Up not handled by view" << llendl; - } - } - - if( !handled ) - { - if (tool) - { - handled = tool->handleMouseUp(x, y, mask); - } - } - - // Always handled as far as the OS is concerned. - return TRUE; + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down); } @@ -829,91 +734,10 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK x = llround((F32)x / mDisplayScale.mV[VX]); y = llround((F32)y / mDisplayScale.mV[VY]); - LLView::sMouseHandlerMessage.clear(); - - if (gDebugClicks) - { - llinfos << "ViewerWindow right mouse down at " << x << "," << y << llendl; - } - - if (gMenuBarView) - { - // stop ALT-key access to menu - gMenuBarView->resetMenuTrigger(); - } - - mRightMouseDown = TRUE; - - // Make sure we get a coresponding mouseup event, even if the mouse leaves the window - mWindow->captureMouse(); - - // Hide tooltips - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mousedown - if (gHoverView) - { - gHoverView->cancelHover(); - } - - // Don't let the user move the mouse out of the window until mouse up. - if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(TRUE); - } - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Down handled by captor " << mouse_captor->getName() << llendl; - } - return mouse_captor->handleRightMouseDown(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - if (top_ctrl->pointInView(local_x, local_y)) - { - return top_ctrl->handleRightMouseDown(local_x, local_y, mask); - } - else - { - gFocusMgr.setTopCtrl(NULL); - } - } - - if( mRootView->handleRightMouseDown(x, y, mask) ) - { - if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Down" << LLView::sMouseHandlerMessage << llendl; - } - return TRUE; - } - else if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Down not handled by view" << llendl; - } - - if(LLToolMgr::getInstance()->getCurrentTool()->handleRightMouseDown( x, y, mask ) ) - { - // This is necessary to force clicks in the world to cause edit - // boxes that might have keyboard focus to relinquish it, and hence - // cause a commit to update their value. JC - gFocusMgr.setKeyboardFocus(NULL); - return TRUE; - } + BOOL down = TRUE; + BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); + if (handle) + return handle; // *HACK: this should be rolled into the composite tool logic, not // hardcoded at the top level. @@ -931,107 +755,27 @@ BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { - S32 x = pos.mX; - S32 y = pos.mY; - x = llround((F32)x / mDisplayScale.mV[VX]); - y = llround((F32)y / mDisplayScale.mV[VY]); - - LLView::sMouseHandlerMessage.clear(); - - // Don't care about caps lock for mouse events. - if (gDebugClicks) - { - llinfos << "ViewerWindow right mouse up" << llendl; - } - - mRightMouseDown = FALSE; - - // Indicate mouse was active - gMouseIdleTimer.reset(); - - // Hide tooltips on mouseup - if( mToolTip ) - { - mToolTip->setVisible( FALSE ); - } - - // Also hide hover info on mouseup - if (gHoverView) gHoverView->cancelHover(); - - BOOL handled = FALSE; - - mWindow->releaseMouse(); - - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - - if( tool->clipMouseWhenDown() ) - { - mWindow->setMouseClipping(FALSE); - } - - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); - if( mouse_captor ) - { - S32 local_x; - S32 local_y; - mouse_captor->screenPointToLocal( x, y, &local_x, &local_y ); - if (LLView::sDebugMouseHandling) - { - llinfos << "Right Mouse Up handled by captor " << mouse_captor->getName() << llendl; - } - return mouse_captor->handleRightMouseUp(local_x, local_y, mask); - } - - LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - if (top_ctrl) - { - S32 local_x, local_y; - top_ctrl->screenPointToLocal( x, y, &local_x, &local_y ); - handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleRightMouseUp(local_x, local_y, mask); - } - - if( !handled ) - { - handled = mRootView->handleRightMouseUp(x, y, mask); - } - - if (LLView::sDebugMouseHandling) - { - if (handled) - { - llinfos << "Right Mouse Up" << LLView::sMouseHandlerMessage << llendl; - } - else - { - llinfos << "Right Mouse Up not handled by view" << llendl; - } - } - - if( !handled ) - { - if (tool) - { - handled = tool->handleRightMouseUp(x, y, mask); - } - } - - // Always handled as far as the OS is concerned. - return TRUE; + BOOL down = FALSE; + return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down); } BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask) { + BOOL down = TRUE; gVoiceClient->middleMouseState(true); - - // Always handled as far as the OS is concerned. + handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + + // Always handled as far as the OS is concerned. return TRUE; } - + BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask) { + BOOL down = FALSE; gVoiceClient->middleMouseState(false); - - // Always handled as far as the OS is concerned. + handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down); + + // Always handled as far as the OS is concerned. return TRUE; } @@ -1404,6 +1148,7 @@ LLViewerWindow::LLViewerWindow( mWindowRect(0, height, width, 0), mVirtualWindowRect(0, height, width, 0), mLeftMouseDown(FALSE), + mMiddleMouseDown(FALSE), mRightMouseDown(FALSE), mToolTip(NULL), mToolTipBlocked(FALSE), diff --git a/linden/indra/newview/llviewerwindow.h b/linden/indra/newview/llviewerwindow.h index ab2dd4e..40368f8 100644 --- a/linden/indra/newview/llviewerwindow.h +++ b/linden/indra/newview/llviewerwindow.h @@ -47,6 +47,7 @@ #include "lltimer.h" #include "llstat.h" #include "llalertdialog.h" +#include "llmousehandler.h" class LLView; class LLViewerObject; @@ -57,7 +58,6 @@ class LLVelocityBar; class LLTextBox; class LLImageRaw; class LLHUDIcon; -class LLMouseHandler; #define PICK_HALF_WIDTH 5 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -81,7 +81,7 @@ public: static bool isFlora(LLViewerObject* object); - typedef enum e_pick_type + typedef enum { PICK_OBJECT, PICK_FLORA, @@ -150,6 +150,7 @@ public: /*virtual*/ BOOL handleTranslatedKeyUp(KEY key, MASK mask); /*virtual*/ void handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); /*virtual*/ BOOL handleUnicodeChar(llwchar uni_char, MASK mask); // NOT going to handle extended + /*virtual*/ BOOL handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down); /*virtual*/ BOOL handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); /*virtual*/ BOOL handleCloseRequest(LLWindow *window); @@ -212,6 +213,7 @@ public: LLCoordGL getCurrentMouseDelta() const { return mCurrentMouseDelta; } LLStat * getMouseVelocityStat() { return &mMouseVelocityStat; } BOOL getLeftMouseDown() const { return mLeftMouseDown; } + BOOL getMiddleMouseDown() const { return mMiddleMouseDown; } BOOL getRightMouseDown() const { return mRightMouseDown; } const LLPickInfo& getLastPick() const { return mLastPick; } @@ -279,7 +281,7 @@ public: // snapshot functionality. // perhaps some of this should move to llfloatershapshot? -MG - typedef enum e_snapshot_type + typedef enum { SNAPSHOT_TYPE_COLOR, SNAPSHOT_TYPE_DEPTH, @@ -397,6 +399,7 @@ protected: LLCoordGL mCurrentMouseDelta; //amount mouse moved this frame LLStat mMouseVelocityStat; BOOL mLeftMouseDown; + BOOL mMiddleMouseDown; BOOL mRightMouseDown; LLProgressView *mProgressView; -- cgit v1.1