aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llwindow/llwindowmacosx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linden/indra/llwindow/llwindowmacosx.cpp')
-rw-r--r--linden/indra/llwindow/llwindowmacosx.cpp428
1 files changed, 378 insertions, 50 deletions
diff --git a/linden/indra/llwindow/llwindowmacosx.cpp b/linden/indra/llwindow/llwindowmacosx.cpp
index 93ef46b..f522abb 100644
--- a/linden/indra/llwindow/llwindowmacosx.cpp
+++ b/linden/indra/llwindow/llwindowmacosx.cpp
@@ -12,12 +12,12 @@
12 * ("GPL"), unless you have obtained a separate licensing agreement 12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of 13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or 14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlife.com/developers/opensource/gplv2 15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 * 16 *
17 * There are special exceptions to the terms and conditions of the GPL as 17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception 18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or 19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at http://secondlife.com/developers/opensource/flossexception 20 * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
21 * 21 *
22 * By copying, modifying or distributing this software, you acknowledge 22 * By copying, modifying or distributing this software, you acknowledge
23 * that you have read and understood your obligations described above, 23 * that you have read and understood your obligations described above,
@@ -48,6 +48,7 @@
48#include "indra_constants.h" 48#include "indra_constants.h"
49 49
50#include "llwindowmacosx-objc.h" 50#include "llwindowmacosx-objc.h"
51#include "llpreeditor.h"
51 52
52extern BOOL gDebugWindowProc; 53extern BOOL gDebugWindowProc;
53 54
@@ -69,7 +70,6 @@ const S32 MAX_NUM_RESOLUTIONS = 32;
69void show_window_creation_error(const char* title) 70void show_window_creation_error(const char* title)
70{ 71{
71 llwarns << title << llendl; 72 llwarns << title << llendl;
72 shell_open( "help/window_creation_error.html");
73 /* 73 /*
74 OSMessageBox( 74 OSMessageBox(
75 "Second Life is unable to run because it can't set up your display.\n" 75 "Second Life is unable to run because it can't set up your display.\n"
@@ -172,8 +172,22 @@ static EventTypeSpec WindowHandlerEventList[] =
172 { kEventClassKeyboard, kEventRawKeyModifiersChanged }, 172 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
173 173
174 // Text input events 174 // Text input events
175 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } 175 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
176 176 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
177 { kEventClassTextInput, kEventTextInputOffsetToPos },
178 { kEventClassTextInput, kEventTextInputPosToOffset },
179 { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
180 { kEventClassTextInput, kEventTextInputGetSelectedText },
181 { kEventClassTextInput, kEventTextInputFilterText },
182
183 // TSM Document Access events (advanced input method support)
184 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
185 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
186 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
187 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
188 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
189 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
190 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
177}; 191};
178 192
179static EventTypeSpec GlobalHandlerEventList[] = 193static EventTypeSpec GlobalHandlerEventList[] =
@@ -195,7 +209,22 @@ static EventTypeSpec GlobalHandlerEventList[] =
195 { kEventClassKeyboard, kEventRawKeyModifiersChanged }, 209 { kEventClassKeyboard, kEventRawKeyModifiersChanged },
196 210
197 // Text input events 211 // Text input events
198 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent } 212 { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
213 { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
214 { kEventClassTextInput, kEventTextInputOffsetToPos },
215 { kEventClassTextInput, kEventTextInputPosToOffset },
216 { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
217 { kEventClassTextInput, kEventTextInputGetSelectedText },
218 { kEventClassTextInput, kEventTextInputFilterText },
219
220 // TSM Document Access events (advanced input method support)
221 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
222 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
223 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
224 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
225 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
226 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
227 { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
199}; 228};
200 229
201static EventTypeSpec CommandHandlerEventList[] = 230static EventTypeSpec CommandHandlerEventList[] =
@@ -246,6 +275,7 @@ LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width,
246 mLanguageTextInputAllowed = FALSE; 275 mLanguageTextInputAllowed = FALSE;
247 mTSMScriptCode = 0; 276 mTSMScriptCode = 0;
248 mTSMLangCode = 0; 277 mTSMLangCode = 0;
278 mPreeditor = NULL;
249 279
250 // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state. 280 // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state.
251 // Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state. 281 // Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state.
@@ -497,15 +527,16 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
497 mTSMDocument = NULL; 527 mTSMDocument = NULL;
498 } 528 }
499 static InterfaceTypeList types = { kUnicodeDocument }; 529 static InterfaceTypeList types = { kUnicodeDocument };
500 OSErr err = NewTSMDocument(1, types, &mTSMDocument, 0); 530 err = NewTSMDocument(1, types, &mTSMDocument, 0);
501 if (err != noErr) 531 if (err != noErr)
502 { 532 {
503 llwarns << "createContext: couldn't create a TSMDocument (" << err << ")" << llendl; 533 llwarns << "createContext: couldn't create a TSMDocument (" << err << ")" << llendl;
504 } 534 }
505 if (mTSMDocument) 535 if (mTSMDocument)
506 { 536 {
507 UseInputWindow(mTSMDocument, TRUE);
508 ActivateTSMDocument(mTSMDocument); 537 ActivateTSMDocument(mTSMDocument);
538 UseInputWindow(mTSMDocument, FALSE);
539 allowLanguageTextInput(NULL, FALSE);
509 } 540 }
510 } 541 }
511 542
@@ -703,7 +734,6 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
703 if (check_for_card(RENDERER, CARD_LIST[i])) 734 if (check_for_card(RENDERER, CARD_LIST[i]))
704 { 735 {
705 close(); 736 close();
706 shell_open( "help/unsupported_card.html" );
707 return FALSE; 737 return FALSE;
708 } 738 }
709 } 739 }
@@ -1949,6 +1979,141 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
1949 { 1979 {
1950 switch (evtKind) 1980 switch (evtKind)
1951 { 1981 {
1982 case kEventTextInputUpdateActiveInputArea:
1983 {
1984 EventParamType param_type;
1985
1986 long fix_len;
1987 UInt32 text_len;
1988 if (mPreeditor
1989 && (result = GetEventParameter(event, kEventParamTextInputSendFixLen,
1990 typeLongInteger, &param_type, sizeof(fix_len), NULL, &fix_len)) == noErr
1991 && typeLongInteger == param_type
1992 && (result = GetEventParameter(event, kEventParamTextInputSendText,
1993 typeUnicodeText, &param_type, 0, &text_len, NULL)) == noErr
1994 && typeUnicodeText == param_type)
1995 {
1996 // Handle an optional (but essential to facilitate TSMDA) ReplaceRange param.
1997 CFRange range;
1998 if (GetEventParameter(event, kEventParamTextInputSendReplaceRange,
1999 typeCFRange, &param_type, sizeof(range), NULL, &range) == noErr
2000 && typeCFRange == param_type)
2001 {
2002 // Although the spec. is unclear, replace range should
2003 // not present when there is an active preedit. We just
2004 // ignore the case. markAsPreedit will detect the case and warn it.
2005 const LLWString & text = mPreeditor->getWText();
2006 const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location);
2007 const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length);
2008 mPreeditor->markAsPreedit(location, length);
2009 }
2010 mPreeditor->resetPreedit();
2011
2012 // Receive the text from input method.
2013 U16 *const text = new U16[text_len / sizeof(U16)];
2014 GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, NULL, text_len, NULL, text);
2015 if (fix_len < 0)
2016 {
2017 // Do we still need this? Seems obsolete...
2018 fix_len = text_len;
2019 }
2020 const LLWString fix_string
2021 = utf16str_to_wstring(llutf16string(text, fix_len / sizeof(U16)));
2022 const LLWString preedit_string
2023 = utf16str_to_wstring(llutf16string(text + fix_len / sizeof(U16), (text_len - fix_len) / sizeof(U16)));
2024 delete[] text;
2025
2026 // Handle fixed (comitted) string.
2027 if (fix_string.length() > 0)
2028 {
2029 for (LLWString::const_iterator i = fix_string.begin(); i != fix_string.end(); i++)
2030 {
2031 mPreeditor->handleUnicodeCharHere(*i, FALSE);
2032 }
2033 }
2034
2035 // Receive the segment info and caret position.
2036 LLPreeditor::segment_lengths_t preedit_segment_lengths;
2037 LLPreeditor::standouts_t preedit_standouts;
2038 S32 caret_position = preedit_string.length();
2039 UInt32 text_range_array_size;
2040 if (GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
2041 &param_type, 0, &text_range_array_size, NULL) == noErr
2042 && typeTextRangeArray == param_type
2043 && text_range_array_size > sizeof(TextRangeArray))
2044 {
2045 // TextRangeArray is a variable-length struct.
2046 TextRangeArray * const text_range_array = (TextRangeArray *) new char[text_range_array_size];
2047 GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
2048 NULL, text_range_array_size, NULL, text_range_array);
2049
2050 // WARNING: We assume ranges are in ascending order,
2051 // although the condition is undocumented. It seems
2052 // OK to assume this. I also assumed
2053 // the ranges are contiguous in previous versions, but I
2054 // have heard a rumore that older versions os ATOK may
2055 // return ranges with some _gap_. I don't know whether
2056 // it is true, but I'm preparing my code for the case.
2057
2058 const S32 ranges = text_range_array->fNumOfRanges;
2059 preedit_segment_lengths.reserve(ranges);
2060 preedit_standouts.reserve(ranges);
2061
2062 S32 last_bytes = 0;
2063 S32 last_utf32 = 0;
2064 for (S32 i = 0; i < ranges; i++)
2065 {
2066 const TextRange &range = text_range_array->fRange[i];
2067 if (range.fStart > last_bytes)
2068 {
2069 const S32 length_utf16 = (range.fStart - last_bytes) / sizeof(U16);
2070 const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
2071 preedit_segment_lengths.push_back(length_utf32);
2072 preedit_standouts.push_back(FALSE);
2073 last_utf32 += length_utf32;
2074 }
2075 if (range.fEnd > range.fStart)
2076 {
2077 const S32 length_utf16 = (range.fEnd - range.fStart) / sizeof(U16);
2078 const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
2079 preedit_segment_lengths.push_back(length_utf32);
2080 preedit_standouts.push_back(
2081 kTSMHiliteSelectedRawText == range.fHiliteStyle
2082 || kTSMHiliteSelectedConvertedText == range.fHiliteStyle
2083 || kTSMHiliteSelectedText == range.fHiliteStyle);
2084 last_utf32 += length_utf32;
2085 }
2086 if (kTSMHiliteCaretPosition == range.fHiliteStyle)
2087 {
2088 caret_position = last_utf32;
2089 }
2090 last_bytes = range.fEnd;
2091 }
2092 if (preedit_string.length() > last_utf32)
2093 {
2094 preedit_segment_lengths.push_back(preedit_string.length() - last_utf32);
2095 preedit_standouts.push_back(FALSE);
2096 }
2097
2098 delete[] (char *) text_range_array;
2099 }
2100
2101 // Handle preedit string.
2102 if (preedit_string.length() > 0)
2103 {
2104 if (preedit_segment_lengths.size() == 0)
2105 {
2106 preedit_segment_lengths.push_back(preedit_string.length());
2107 preedit_standouts.push_back(FALSE);
2108 }
2109 mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
2110 }
2111
2112 result = noErr;
2113 }
2114 }
2115 break;
2116
1952 case kEventTextInputUnicodeForKeyEvent: 2117 case kEventTextInputUnicodeForKeyEvent:
1953 { 2118 {
1954 UInt32 modifiers = 0; 2119 UInt32 modifiers = 0;
@@ -2021,6 +2186,63 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
2021 result = err; 2186 result = err;
2022 } 2187 }
2023 break; 2188 break;
2189
2190 case kEventTextInputOffsetToPos:
2191 {
2192 EventParamType param_type;
2193 long offset;
2194 if (mPreeditor
2195 && GetEventParameter(event, kEventParamTextInputSendTextOffset, typeLongInteger,
2196 &param_type, sizeof(offset), NULL, &offset) == noErr
2197 && typeLongInteger == param_type)
2198 {
2199 S32 preedit, preedit_length;
2200 mPreeditor->getPreeditRange(&preedit, &preedit_length);
2201 const LLWString & text = mPreeditor->getWText();
2202
2203 LLCoordGL caret_coord;
2204 LLRect preedit_bounds;
2205 if (0 <= offset
2206 && mPreeditor->getPreeditLocation(wstring_wstring_length_from_utf16_length(text, preedit, offset / sizeof(U16)),
2207 &caret_coord, &preedit_bounds, NULL))
2208 {
2209 LLCoordGL caret_base_coord(caret_coord.mX, preedit_bounds.mBottom);
2210 LLCoordScreen caret_base_coord_screen;
2211 convertCoords(caret_base_coord, &caret_base_coord_screen);
2212 Point qd_point;
2213 qd_point.h = caret_base_coord_screen.mX;
2214 qd_point.v = caret_base_coord_screen.mY;
2215 SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, sizeof(qd_point), &qd_point);
2216
2217 short line_height = (short) preedit_bounds.getHeight();
2218 SetEventParameter(event, kEventParamTextInputReplyLineHeight, typeShortInteger, sizeof(line_height), &line_height);
2219
2220 result = noErr;
2221 }
2222 else
2223 {
2224 result = errOffsetInvalid;
2225 }
2226 }
2227 }
2228 break;
2229
2230 case kEventTextInputGetSelectedText:
2231 {
2232 if (mPreeditor)
2233 {
2234 S32 selection, selection_length;
2235 mPreeditor->getSelectionRange(&selection, &selection_length);
2236 if (selection_length)
2237 {
2238 const LLWString text = mPreeditor->getWText().substr(selection, selection_length);
2239 const llutf16string text_utf16 = wstring_to_utf16str(text);
2240 result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText,
2241 text_utf16.length() * sizeof(U16), text_utf16.c_str());
2242 }
2243 }
2244 }
2245 break;
2024 } 2246 }
2025 } 2247 }
2026 break; 2248 break;
@@ -2194,6 +2416,13 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
2194 switch (evtKind) 2416 switch (evtKind)
2195 { 2417 {
2196 case kEventMouseDown: 2418 case kEventMouseDown:
2419 if (mLanguageTextInputAllowed)
2420 {
2421 // We need to interrupt before handling mouse events,
2422 // so that the fixed string from IM are delivered to
2423 // the currently focused UI component.
2424 interruptLanguageTextInput();
2425 }
2197 switch(button) 2426 switch(button)
2198 { 2427 {
2199 case kEventMouseButtonPrimary: 2428 case kEventMouseButtonPrimary:
@@ -2287,6 +2516,10 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
2287 mCallbacks->handleFocus(this); 2516 mCallbacks->handleFocus(this);
2288 break; 2517 break;
2289 case kEventWindowDeactivated: 2518 case kEventWindowDeactivated:
2519 if (mTSMDocument)
2520 {
2521 DeactivateTSMDocument(mTSMDocument);
2522 }
2290 mCallbacks->handleFocusLost(this); 2523 mCallbacks->handleFocusLost(this);
2291 break; 2524 break;
2292 case kEventWindowBoundsChanging: 2525 case kEventWindowBoundsChanging:
@@ -2359,6 +2592,109 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e
2359 // BringToFront(mWindow); 2592 // BringToFront(mWindow);
2360 // result = noErr; 2593 // result = noErr;
2361 break; 2594 break;
2595
2596 }
2597 break;
2598
2599 case kEventClassTSMDocumentAccess:
2600 if (mPreeditor)
2601 {
2602 switch(evtKind)
2603 {
2604
2605 case kEventTSMDocumentAccessGetLength:
2606 {
2607 // Return the number of UTF-16 units in the text, excluding those for preedit.
2608
2609 S32 preedit, preedit_length;
2610 mPreeditor->getPreeditRange(&preedit, &preedit_length);
2611 const LLWString & text = mPreeditor->getWText();
2612 const CFIndex length = wstring_utf16_length(text, 0, preedit)
2613 + wstring_utf16_length(text, preedit + preedit_length, text.length());
2614 result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length);
2615 }
2616 break;
2617
2618 case kEventTSMDocumentAccessGetSelectedRange:
2619 {
2620 // Return the selected range, excluding preedit.
2621 // In our preeditor, preedit and selection are exclusive, so,
2622 // when it has a preedit, there is no selection and the
2623 // insertion point is on the preedit that corrupses into the
2624 // beginning of the preedit when the preedit was removed.
2625
2626 S32 preedit, preedit_length;
2627 mPreeditor->getPreeditRange(&preedit, &preedit_length);
2628 const LLWString & text = mPreeditor->getWText();
2629
2630 CFRange range;
2631 if (preedit_length)
2632 {
2633 range.location = wstring_utf16_length(text, 0, preedit);
2634 range.length = 0;
2635 }
2636 else
2637 {
2638 S32 selection, selection_length;
2639 mPreeditor->getSelectionRange(&selection, &selection_length);
2640 range.location = wstring_utf16_length(text, 0, selection);
2641 range.length = wstring_utf16_length(text, selection, selection_length);
2642 }
2643
2644 result = SetEventParameter(event, kEventParamTSMDocAccessReplyCharacterRange, typeCFRange, sizeof(range), &range);
2645 }
2646 break;
2647
2648 case kEventTSMDocumentAccessGetCharacters:
2649 {
2650 UniChar *target_pointer;
2651 CFRange range;
2652 EventParamType param_type;
2653 if ((result = GetEventParameter(event, kEventParamTSMDocAccessSendCharacterRange,
2654 typeCFRange, &param_type, sizeof(range), NULL, &range)) == noErr
2655 && typeCFRange == param_type
2656 && (result = GetEventParameter(event, kEventParamTSMDocAccessSendCharactersPtr,
2657 typePtr, &param_type, sizeof(target_pointer), NULL, &target_pointer)) == noErr
2658 && typePtr == param_type)
2659 {
2660 S32 preedit, preedit_length;
2661 mPreeditor->getPreeditRange(&preedit, &preedit_length);
2662 const LLWString & text = mPreeditor->getWText();
2663
2664 // The GetCharacters event of TSMDA has a fundamental flaw;
2665 // An input method need to decide the starting offset and length
2666 // *before* it actually see the contents, so it is impossible
2667 // to guarantee the character-aligned access. The event reply
2668 // has no way to indicate a condition something like "Request
2669 // was not fulfilled due to unaligned access. Please retry."
2670 // Any error sent back to the input method stops use of TSMDA
2671 // entirely during the session...
2672 // We need to simulate very strictly the behaviour as if the
2673 // underlying *text engine* holds the contents in UTF-16.
2674 // I guess this is the reason why Apple repeats saying "all
2675 // text handling application should use UTF-16." They are
2676 // trying to _fix_ the flaw by changing the appliations...
2677 // ... or, domination of UTF-16 in the industry may be a part
2678 // of the company vision, and Apple is trying to force third
2679 // party developers to obey their vision. Remember that use
2680 // of 16 bits per _a_character_ was one of the very fundamental
2681 // Unicode design policy on its early days (during late 80s)
2682 // and the original Unicode design was by two Apple employees...
2683
2684 const llutf16string text_utf16
2685 = wstring_to_utf16str(text, preedit)
2686 + wstring_to_utf16str(text.substr(preedit + preedit_length));
2687
2688 llassert_always(sizeof(U16) == sizeof(UniChar));
2689 llassert(0 <= range.location && 0 <= range.length && range.location + range.length <= text_utf16.length());
2690 memcpy(target_pointer, text_utf16.c_str() + range.location, range.length * sizeof(UniChar));
2691
2692 // Note that result has already been set above.
2693 }
2694 }
2695 break;
2696
2697 }
2362 } 2698 }
2363 break; 2699 break;
2364 } 2700 }
@@ -2862,46 +3198,6 @@ void spawn_web_browser(const char* escaped_url)
2862 } 3198 }
2863} 3199}
2864 3200
2865void shell_open( const char* file_path )
2866{
2867 OSStatus result = noErr;
2868
2869 llinfos << "Opening " << file_path << llendl;
2870 CFURLRef urlRef = NULL;
2871
2872 CFStringRef stringRef = CFStringCreateWithCString(NULL, file_path, kCFStringEncodingUTF8);
2873 if (stringRef)
2874 {
2875 // This will succeed if the string is a full URL, including the http://
2876 // Note that URLs specified this way need to be properly percent-escaped.
2877 urlRef = CFURLCreateWithString(NULL, stringRef, NULL);
2878
2879 if(urlRef == NULL)
2880 {
2881 // This will succeed if the string is a full or partial posix path.
2882 // This will work even if the path contains characters that would need to be percent-escaped
2883 // in the URL (such as spaces).
2884 urlRef = CFURLCreateWithFileSystemPath(NULL, stringRef, kCFURLPOSIXPathStyle, false);
2885 }
2886
2887 CFRelease(stringRef);
2888 }
2889
2890 if (urlRef)
2891 {
2892 result = LSOpenCFURLRef(urlRef, NULL);
2893
2894 if (result != noErr)
2895 {
2896 llinfos << "Error " << result << " on open." << llendl;
2897 }
2898 CFRelease(urlRef);
2899 }
2900 else
2901 {
2902 llinfos << "Error: couldn't create URL." << llendl;
2903 }
2904}
2905 3201
2906BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b) 3202BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b)
2907{ 3203{
@@ -2995,10 +3291,34 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key)
2995 return int_value; // otherwise return the long value 3291 return int_value; // otherwise return the long value
2996} 3292}
2997 3293
2998void LLWindowMacOSX::allowLanguageTextInput(BOOL b) 3294void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
2999{ 3295{
3000 ScriptLanguageRecord script_language; 3296 ScriptLanguageRecord script_language;
3001 3297
3298 if (preeditor != mPreeditor && !b)
3299 {
3300 // This condition may occur by a call to
3301 // setEnabled(BOOL) against LLTextEditor or LLLineEditor
3302 // when the control is not focused.
3303 // We need to silently ignore the case so that
3304 // the language input status of the focused control
3305 // is not disturbed.
3306 return;
3307 }
3308
3309 // Take care of old and new preeditors.
3310 if (preeditor != mPreeditor || !b)
3311 {
3312 // We need to interrupt before updating mPreeditor,
3313 // so that the fix string from input method goes to
3314 // the old preeditor.
3315 if (mLanguageTextInputAllowed)
3316 {
3317 interruptLanguageTextInput();
3318 }
3319 mPreeditor = (b ? preeditor : NULL);
3320 }
3321
3002 if (b == mLanguageTextInputAllowed) 3322 if (b == mLanguageTextInputAllowed)
3003 { 3323 {
3004 return; 3324 return;
@@ -3028,4 +3348,12 @@ void LLWindowMacOSX::allowLanguageTextInput(BOOL b)
3028 } 3348 }
3029} 3349}
3030 3350
3351void LLWindowMacOSX::interruptLanguageTextInput()
3352{
3353 if (mTSMDocument)
3354 {
3355 FixTSMDocument(mTSMDocument);
3356 }
3357}
3358
3031#endif // LL_DARWIN 3359#endif // LL_DARWIN