summaryrefslogtreecommitdiff
path: root/indra/llwindow
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow')
-rwxr-xr-xindra/llwindow/CMakeLists.txt3
-rw-r--r--indra/llwindow/llappdelegate-objc.h30
-rwxr-xr-xindra/llwindow/llkeyboard.h5
-rwxr-xr-xindra/llwindow/llkeyboardheadless.cpp7
-rwxr-xr-xindra/llwindow/llkeyboardheadless.h3
-rwxr-xr-xindra/llwindow/llkeyboardmacosx.cpp37
-rwxr-xr-xindra/llwindow/llkeyboardmacosx.h10
-rw-r--r--indra/llwindow/llopenglview-objc.h91
-rw-r--r--indra/llwindow/llopenglview-objc.mm644
-rwxr-xr-xindra/llwindow/llwindowmacosx-objc.h110
-rwxr-xr-xindra/llwindow/llwindowmacosx-objc.mm303
-rwxr-xr-xindra/llwindow/llwindowmacosx.cpp2694
-rwxr-xr-xindra/llwindow/llwindowmacosx.h65
13 files changed, 1738 insertions, 2264 deletions
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index 4c6e706119..aec6d7af4a 100755
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -109,11 +109,14 @@ if (DARWIN)
llkeyboardmacosx.cpp
llwindowmacosx.cpp
llwindowmacosx-objc.mm
+ llopenglview-objc.mm
)
list(APPEND llwindow_HEADER_FILES
llkeyboardmacosx.h
llwindowmacosx.h
llwindowmacosx-objc.h
+ llopenglview-objc.h
+ llappdelegate-objc.h
)
# We use a bunch of deprecated system APIs.
diff --git a/indra/llwindow/llappdelegate-objc.h b/indra/llwindow/llappdelegate-objc.h
new file mode 100644
index 0000000000..a6fb77d93f
--- /dev/null
+++ b/indra/llwindow/llappdelegate-objc.h
@@ -0,0 +1,30 @@
+//
+// LLAppDelegate.h
+// SecondLife
+//
+// Created by Geenz on 12/16/12.
+//
+//
+
+#import <Cocoa/Cocoa.h>
+#import "llopenglview-objc.h"
+
+@interface LLAppDelegate : NSObject <NSApplicationDelegate> {
+ LLNSWindow *window;
+ NSWindow *inputWindow;
+ LLNonInlineTextView *inputView;
+ NSTimer *frameTimer;
+ NSString *currentInputLanguage;
+}
+
+@property (assign) IBOutlet LLNSWindow *window;
+@property (assign) IBOutlet NSWindow *inputWindow;
+@property (assign) IBOutlet LLNonInlineTextView *inputView;
+
+@property (retain) NSString *currentInputLanguage;
+
+- (void) mainLoop;
+- (void) showInputWindow:(bool)show withEvent:(NSEvent*)textEvent;
+- (void) languageUpdated;
+- (bool) romanScript;
+@end
diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h
index c155c1b362..92449c123f 100755
--- a/indra/llwindow/llkeyboard.h
+++ b/indra/llwindow/llkeyboard.h
@@ -82,6 +82,11 @@ public:
virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0;
virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0;
+
+#ifdef LL_DARWIN
+ // We only actually use this for OS X.
+ virtual void handleModifier(MASK mask) = 0;
+#endif // LL_DARWIN
// Asynchronously poll the control, alt, and shift keys and set the
// appropriate internal key masks.
diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp
index c87617c9ff..a1b6b294e0 100755
--- a/indra/llwindow/llkeyboardheadless.cpp
+++ b/indra/llwindow/llkeyboardheadless.cpp
@@ -45,6 +45,13 @@ BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask)
MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event)
{ return MASK_NONE; }
+#ifdef LL_DARWIN
+void LLKeyboardHeadless::handleModifier(MASK mask)
+{
+
+}
+#endif
+
void LLKeyboardHeadless::scanKeyboard()
{
for (S32 key = 0; key < KEY_COUNT; key++)
diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h
index 4e666f8ce8..8ed28ace90 100755
--- a/indra/llwindow/llkeyboardheadless.h
+++ b/indra/llwindow/llkeyboardheadless.h
@@ -40,6 +40,9 @@ public:
/*virtual*/ void resetMaskKeys();
/*virtual*/ MASK currentMask(BOOL for_mouse_event);
/*virtual*/ void scanKeyboard();
+#ifdef LL_DARWIN
+ /*virtual*/ void handleModifier(MASK mask);
+#endif
};
#endif
diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp
index 7f8f303517..85bb7b9aeb 100755
--- a/indra/llwindow/llkeyboardmacosx.cpp
+++ b/indra/llwindow/llkeyboardmacosx.cpp
@@ -30,7 +30,7 @@
#include "llkeyboardmacosx.h"
#include "llwindowcallbacks.h"
-#include <Carbon/Carbon.h>
+#include "llwindowmacosx-objc.h"
LLKeyboardMacOSX::LLKeyboardMacOSX()
{
@@ -162,23 +162,25 @@ LLKeyboardMacOSX::LLKeyboardMacOSX()
void LLKeyboardMacOSX::resetMaskKeys()
{
- U32 mask = GetCurrentEventKeyModifiers();
+ U32 mask = getModifiers();
// MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys().
// It looks a bit suspicious, as it won't correct for keys that have been released.
// Is this the way it's supposed to work?
+
+ // We apply the modifier masks directly within getModifiers. So check to see which masks we've applied.
- if(mask & shiftKey)
+ if(mask & MAC_SHIFT_KEY)
{
mKeyLevel[KEY_SHIFT] = TRUE;
}
- if(mask & (controlKey))
+ if(mask & MAC_CTRL_KEY)
{
mKeyLevel[KEY_CONTROL] = TRUE;
}
- if(mask & optionKey)
+ if(mask & MAC_ALT_KEY)
{
mKeyLevel[KEY_ALT] = TRUE;
}
@@ -196,22 +198,27 @@ static BOOL translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &out
}
*/
+void LLKeyboardMacOSX::handleModifier(MASK mask)
+{
+ updateModifiers(mask);
+}
+
MASK LLKeyboardMacOSX::updateModifiers(const U32 mask)
{
// translate the mask
MASK out_mask = 0;
- if(mask & shiftKey)
+ if(mask & MAC_SHIFT_KEY)
{
out_mask |= MASK_SHIFT;
}
- if(mask & (controlKey | cmdKey))
+ if(mask & (MAC_CTRL_KEY | MAC_CMD_KEY))
{
out_mask |= MASK_CONTROL;
}
- if(mask & optionKey)
+ if(mask & MAC_ALT_KEY)
{
out_mask |= MASK_ALT;
}
@@ -231,7 +238,7 @@ BOOL LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask)
{
handled = handleTranslatedKeyDown(translated_key, translated_mask);
}
-
+
return handled;
}
@@ -255,18 +262,18 @@ BOOL LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask)
MASK LLKeyboardMacOSX::currentMask(BOOL for_mouse_event)
{
MASK result = MASK_NONE;
- U32 mask = GetCurrentEventKeyModifiers();
+ U32 mask = getModifiers();
- if (mask & shiftKey) result |= MASK_SHIFT;
- if (mask & controlKey) result |= MASK_CONTROL;
- if (mask & optionKey) result |= MASK_ALT;
+ if (mask & MAC_SHIFT_KEY) result |= MASK_SHIFT;
+ if (mask & MAC_CTRL_KEY) result |= MASK_CONTROL;
+ if (mask & MAC_ALT_KEY) result |= MASK_ALT;
// For keyboard events, consider Command equivalent to Control
if (!for_mouse_event)
{
- if (mask & cmdKey) result |= MASK_CONTROL;
+ if (mask & MAC_CMD_KEY) result |= MASK_CONTROL;
}
-
+
return result;
}
diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h
index f09ff720ce..f9d014ab70 100755
--- a/indra/llwindow/llkeyboardmacosx.h
+++ b/indra/llwindow/llkeyboardmacosx.h
@@ -29,6 +29,15 @@
#include "llkeyboard.h"
+// These more or less mirror their equivalents in NSEvent.h.
+enum EMacEventKeys {
+ MAC_SHIFT_KEY = 1 << 17,
+ MAC_CTRL_KEY = 1 << 18,
+ MAC_ALT_KEY = 1 << 19,
+ MAC_CMD_KEY = 1 << 20,
+ MAC_FN_KEY = 1 << 23
+};
+
class LLKeyboardMacOSX : public LLKeyboard
{
public:
@@ -40,6 +49,7 @@ public:
/*virtual*/ void resetMaskKeys();
/*virtual*/ MASK currentMask(BOOL for_mouse_event);
/*virtual*/ void scanKeyboard();
+ /*virtual*/ void handleModifier(MASK mask);
protected:
MASK updateModifiers(const U32 mask);
diff --git a/indra/llwindow/llopenglview-objc.h b/indra/llwindow/llopenglview-objc.h
new file mode 100644
index 0000000000..b783c41c0b
--- /dev/null
+++ b/indra/llwindow/llopenglview-objc.h
@@ -0,0 +1,91 @@
+//
+// LLOpenGLView.h
+// SecondLife
+//
+// Created by Geenz on 10/2/12.
+//
+//
+
+#ifndef LLOpenGLView_H
+#define LLOpenGLView_H
+
+#import <Cocoa/Cocoa.h>
+#import <IOKit/IOKitLib.h>
+#import <CoreFoundation/CFBase.h>
+#import <CoreFoundation/CFNumber.h>
+#include <string>
+
+@interface LLOpenGLView : NSOpenGLView <NSTextInputClient>
+{
+ std::string mLastDraggedUrl;
+ unsigned int mModifiers;
+ float mMousePos[2];
+ bool mHasMarkedText;
+ unsigned int mMarkedTextLength;
+ bool mMarkedTextAllowed;
+}
+- (id) initWithSamples:(NSUInteger)samples;
+- (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync;
+- (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync;
+
+- (void)commitCurrentPreedit;
+
+// rebuildContext
+// Destroys and recreates a context with the view's internal format set via setPixelFormat;
+// Use this in event of needing to rebuild a context for whatever reason, without needing to assign a new pixel format.
+- (BOOL) rebuildContext;
+
+// rebuildContextWithFormat
+// Destroys and recreates a context with the specified pixel format.
+- (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format;
+
+// These are mostly just for C++ <-> Obj-C interop. We can manipulate the CGLContext from C++ without reprecussions.
+- (CGLContextObj) getCGLContextObj;
+- (CGLPixelFormatObj*)getCGLPixelFormatObj;
+
+- (unsigned long) getVramSize;
+
+- (void) allowMarkedTextInput:(bool)allowed;
+
+@end
+
+@interface LLUserInputWindow : NSPanel
+
+@end
+
+@interface LLNonInlineTextView : NSTextView
+{
+ LLOpenGLView *glview;
+}
+
+- (void) setGLView:(LLOpenGLView*)view;
+
+@end
+
+@interface LLNSWindow : NSWindow
+
+- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view;
+- (NSPoint)flipPoint:(NSPoint)aPoint;
+
+@end
+
+@interface NSScreen (PointConversion)
+
+/*
+ Returns the screen where the mouse resides
+ */
++ (NSScreen *)currentScreenForMouseLocation;
+
+/*
+ Allows you to convert a point from global coordinates to the current screen coordinates.
+ */
+- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint;
+
+/*
+ Allows to flip the point coordinates, so y is 0 at the top instead of the bottom. x remains the same
+ */
+- (NSPoint)flipPoint:(NSPoint)aPoint;
+
+@end
+
+#endif \ No newline at end of file
diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm
new file mode 100644
index 0000000000..24de5912f0
--- /dev/null
+++ b/indra/llwindow/llopenglview-objc.mm
@@ -0,0 +1,644 @@
+//
+// LLOpenGLView.m
+// SecondLife
+//
+// Created by Geenz on 10/2/12.
+//
+//
+
+#import "llopenglview-objc.h"
+#include "llwindowmacosx-objc.h"
+#import "llappdelegate-objc.h"
+
+@implementation NSScreen (PointConversion)
+
++ (NSScreen *)currentScreenForMouseLocation
+{
+ NSPoint mouseLocation = [NSEvent mouseLocation];
+
+ NSEnumerator *screenEnumerator = [[NSScreen screens] objectEnumerator];
+ NSScreen *screen;
+ while ((screen = [screenEnumerator nextObject]) && !NSMouseInRect(mouseLocation, screen.frame, NO))
+ ;
+
+ return screen;
+}
+
+- (NSPoint)convertPointToScreenCoordinates:(NSPoint)aPoint
+{
+ float normalizedX = fabs(fabs(self.frame.origin.x) - fabs(aPoint.x));
+ float normalizedY = aPoint.y - self.frame.origin.y;
+
+ return NSMakePoint(normalizedX, normalizedY);
+}
+
+- (NSPoint)flipPoint:(NSPoint)aPoint
+{
+ return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+}
+
+@end
+
+attributedStringInfo getSegments(NSAttributedString *str)
+{
+ attributedStringInfo segments;
+ segment_lengths seg_lengths;
+ segment_standouts seg_standouts;
+ NSRange effectiveRange;
+ NSRange limitRange = NSMakeRange(0, [str length]);
+
+ while (limitRange.length > 0) {
+ NSNumber *attr = [str attribute:NSUnderlineStyleAttributeName atIndex:limitRange.location longestEffectiveRange:&effectiveRange inRange:limitRange];
+ limitRange = NSMakeRange(NSMaxRange(effectiveRange), NSMaxRange(limitRange) - NSMaxRange(effectiveRange));
+
+ if (effectiveRange.length <= 0)
+ {
+ effectiveRange.length = 1;
+ }
+
+ if ([attr integerValue] == 2)
+ {
+ seg_lengths.push_back(effectiveRange.length);
+ seg_standouts.push_back(true);
+ } else
+ {
+ seg_lengths.push_back(effectiveRange.length);
+ seg_standouts.push_back(false);
+ }
+ }
+ segments.seg_lengths = seg_lengths;
+ segments.seg_standouts = seg_standouts;
+ return segments;
+}
+
+@implementation LLOpenGLView
+
+- (unsigned long)getVramSize
+{
+ CGLRendererInfoObj info = 0;
+ GLint vram_bytes = 0;
+ int num_renderers = 0;
+ CGLError the_err = CGLQueryRendererInfo (CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), &info, &num_renderers);
+ if(0 == the_err)
+ {
+ CGLDescribeRenderer (info, 0, kCGLRPTextureMemory, &vram_bytes);
+ CGLDestroyRendererInfo (info);
+ }
+ else
+ {
+ vram_bytes = (256 << 20);
+ }
+ return (unsigned long)vram_bytes;
+}
+
+- (void)viewDidMoveToWindow
+{
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(windowResized:) name:NSWindowDidResizeNotification
+ object:[self window]];
+}
+
+- (void)windowResized:(NSNotification *)notification;
+{
+ NSSize size = [self frame].size;
+
+ callResize(size.width, size.height);
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [super dealloc];
+}
+
+- (id) init
+{
+ return [self initWithFrame:[self bounds] withSamples:2 andVsync:TRUE];
+}
+
+- (id) initWithSamples:(NSUInteger)samples
+{
+ return [self initWithFrame:[self bounds] withSamples:samples andVsync:TRUE];
+}
+
+- (id) initWithSamples:(NSUInteger)samples andVsync:(BOOL)vsync
+{
+ return [self initWithFrame:[self bounds] withSamples:samples andVsync:vsync];
+}
+
+- (id) initWithFrame:(NSRect)frame withSamples:(NSUInteger)samples andVsync:(BOOL)vsync
+{
+ [self registerForDraggedTypes:[NSArray arrayWithObject:NSURLPboardType]];
+ [self initWithFrame:frame];
+
+ // Initialize with a default "safe" pixel format that will work with versions dating back to OS X 10.6.
+ // Any specialized pixel formats, i.e. a core profile pixel format, should be initialized through rebuildContextWithFormat.
+ // 10.7 and 10.8 don't really care if we're defining a profile or not. If we don't explicitly request a core or legacy profile, it'll always assume a legacy profile (for compatibility reasons).
+ NSOpenGLPixelFormatAttribute attrs[] = {
+ NSOpenGLPFANoRecovery,
+ NSOpenGLPFADoubleBuffer,
+ NSOpenGLPFAClosestPolicy,
+ NSOpenGLPFAAccelerated,
+ NSOpenGLPFASampleBuffers, (samples > 0 ? 1 : 0),
+ NSOpenGLPFASamples, samples,
+ NSOpenGLPFAStencilSize, 8,
+ NSOpenGLPFADepthSize, 24,
+ NSOpenGLPFAAlphaSize, 8,
+ NSOpenGLPFAColorSize, 24,
+ 0
+ };
+
+ NSOpenGLPixelFormat *pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease];
+
+ if (pixelFormat == nil)
+ {
+ NSLog(@"Failed to create pixel format!", nil);
+ return nil;
+ }
+
+ NSOpenGLContext *glContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
+
+ if (glContext == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return nil;
+ }
+
+ [self setPixelFormat:pixelFormat];
+
+ [self setOpenGLContext:glContext];
+
+ [glContext setView:self];
+
+ [glContext makeCurrentContext];
+
+ if (vsync)
+ {
+ [glContext setValues:(const GLint*)1 forParameter:NSOpenGLCPSwapInterval];
+ } else {
+ [glContext setValues:(const GLint*)0 forParameter:NSOpenGLCPSwapInterval];
+ }
+
+ return self;
+}
+
+- (BOOL) rebuildContext
+{
+ return [self rebuildContextWithFormat:[self pixelFormat]];
+}
+
+- (BOOL) rebuildContextWithFormat:(NSOpenGLPixelFormat *)format
+{
+ NSOpenGLContext *ctx = [self openGLContext];
+
+ [ctx clearDrawable];
+ [ctx initWithFormat:format shareContext:nil];
+
+ if (ctx == nil)
+ {
+ NSLog(@"Failed to create OpenGL context!", nil);
+ return false;
+ }
+
+ [self setOpenGLContext:ctx];
+ [ctx setView:self];
+ [ctx makeCurrentContext];
+ return true;
+}
+
+- (CGLContextObj)getCGLContextObj
+{
+ NSOpenGLContext *ctx = [self openGLContext];
+ return (CGLContextObj)[ctx CGLContextObj];
+}
+
+- (CGLPixelFormatObj*)getCGLPixelFormatObj
+{
+ NSOpenGLPixelFormat *fmt = [self pixelFormat];
+ return (CGLPixelFormatObj*)[fmt CGLPixelFormatObj];
+}
+
+// Various events can be intercepted by our view, thus not reaching our window.
+// Intercept these events, and pass them to the window as needed. - Geenz
+
+- (void) mouseDown:(NSEvent *)theEvent
+{
+ if ([theEvent clickCount] >= 2)
+ {
+ callDoubleClick(mMousePos, mModifiers);
+ } else if ([theEvent clickCount] == 1) {
+ callLeftMouseDown(mMousePos, mModifiers);
+ }
+}
+
+- (void) mouseUp:(NSEvent *)theEvent
+{
+ callLeftMouseUp(mMousePos, mModifiers);
+}
+
+- (void) rightMouseDown:(NSEvent *)theEvent
+{
+ callRightMouseDown(mMousePos, mModifiers);
+}
+
+- (void) rightMouseUp:(NSEvent *)theEvent
+{
+ callRightMouseUp(mMousePos, mModifiers);
+}
+
+- (void)mouseMoved:(NSEvent *)theEvent
+{
+ float mouseDeltas[2] = {
+ [theEvent deltaX],
+ [theEvent deltaY]
+ };
+
+ callDeltaUpdate(mouseDeltas, 0);
+
+ NSPoint mPoint = [theEvent locationInWindow];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseMoved(mMousePos, 0);
+}
+
+// NSWindow doesn't trigger mouseMoved when the mouse is being clicked and dragged.
+// Use mouseDragged for situations like this to trigger our movement callback instead.
+
+- (void) mouseDragged:(NSEvent *)theEvent
+{
+ // Trust the deltas supplied by NSEvent.
+ // The old CoreGraphics APIs we previously relied on are now flagged as obsolete.
+ // NSEvent isn't obsolete, and provides us with the correct deltas.
+ float mouseDeltas[2] = {
+ [theEvent deltaX],
+ [theEvent deltaY]
+ };
+
+ callDeltaUpdate(mouseDeltas, 0);
+
+ NSPoint mPoint = [theEvent locationInWindow];
+ mMousePos[0] = mPoint.x;
+ mMousePos[1] = mPoint.y;
+ callMouseMoved(mMousePos, 0);
+}
+
+- (void) otherMouseDown:(NSEvent *)theEvent
+{
+ callMiddleMouseDown(mMousePos, mModifiers);
+}
+
+- (void) otherMouseUp:(NSEvent *)theEvent
+{
+ callMiddleMouseUp(mMousePos, mModifiers);
+}
+
+- (void) otherMouseDragged:(NSEvent *)theEvent
+{
+
+}
+
+- (void) scrollWheel:(NSEvent *)theEvent
+{
+ callScrollMoved(-[theEvent deltaY]);
+}
+
+- (void) mouseExited:(NSEvent *)theEvent
+{
+ callMouseExit();
+}
+
+- (void) keyUp:(NSEvent *)theEvent
+{
+ callKeyUp([theEvent keyCode], mModifiers);
+}
+
+- (void) keyDown:(NSEvent *)theEvent
+{
+ uint keycode = [theEvent keyCode];
+ bool acceptsText = callKeyDown(keycode, mModifiers);
+ if (acceptsText &&
+ !mMarkedTextAllowed &&
+ ![(LLAppDelegate*)[NSApp delegate] romanScript] &&
+ [[theEvent charactersIgnoringModifiers] characterAtIndex:0] != NSDeleteCharacter &&
+ [[theEvent charactersIgnoringModifiers] characterAtIndex:0] != NSBackspaceCharacter)
+ {
+ [(LLAppDelegate*)[NSApp delegate] showInputWindow:true withEvent:theEvent];
+ } else
+ {
+ [[self inputContext] handleEvent:theEvent];
+ }
+
+ if ([[theEvent charactersIgnoringModifiers] characterAtIndex:0] == NSCarriageReturnCharacter ||
+ [[theEvent charactersIgnoringModifiers] characterAtIndex:0] == NSEnterCharacter)
+ {
+ // callKeyDown won't return the value we expect for enter or return. Handle them as a separate case.
+ [[self inputContext] handleEvent:theEvent];
+ }
+
+ // OS X intentionally does not send us key-up information on cmd-key combinations.
+ // This behaviour is not a bug, and only applies to cmd-combinations (no others).
+ // Since SL assumes we receive those, we fake it here.
+ if (mModifiers & NSCommandKeyMask)
+ {
+ callKeyUp([theEvent keyCode], mModifiers);
+ }
+}
+
+- (void)flagsChanged:(NSEvent *)theEvent {
+ mModifiers = [theEvent modifierFlags];
+ callModifier([theEvent modifierFlags]);
+}
+
+- (BOOL) acceptsFirstResponder
+{
+ return YES;
+}
+
+- (NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender
+{
+ NSPasteboard *pboard;
+ NSDragOperation sourceDragMask;
+
+ sourceDragMask = [sender draggingSourceOperationMask];
+
+ pboard = [sender draggingPasteboard];
+
+ if ([[pboard types] containsObject:NSURLPboardType])
+ {
+ if (sourceDragMask & NSDragOperationLink) {
+ NSURL *fileUrl = [[pboard readObjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:[NSDictionary dictionary]] objectAtIndex:0];
+ mLastDraggedUrl = [[fileUrl absoluteString] UTF8String];
+ return NSDragOperationLink;
+ }
+ }
+ return NSDragOperationNone;
+}
+
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
+{
+ callHandleDragUpdated(mLastDraggedUrl);
+
+ return NSDragOperationLink;
+}
+
+- (void) draggingExited:(id<NSDraggingInfo>)sender
+{
+ callHandleDragExited(mLastDraggedUrl);
+}
+
+- (BOOL)prepareForDragOperation:(id < NSDraggingInfo >)sender
+{
+ return YES;
+}
+
+- (BOOL) performDragOperation:(id<NSDraggingInfo>)sender
+{
+ callHandleDragDropped(mLastDraggedUrl);
+ return true;
+}
+
+- (BOOL)hasMarkedText
+{
+ return mHasMarkedText;
+}
+
+- (NSRange)markedRange
+{
+ int range[2];
+ getPreeditMarkedRange(&range[0], &range[1]);
+ return NSMakeRange(range[0], range[1]);
+}
+
+- (NSRange)selectedRange
+{
+ int range[2];
+ getPreeditSelectionRange(&range[0], &range[1]);
+ return NSMakeRange(range[0], range[1]);
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+ if ([aString class] == NSClassFromString(@"NSConcreteMutableAttributedString"))
+ {
+ if (mMarkedTextAllowed)
+ {
+ unsigned int selected[2] = {
+ selectedRange.location,
+ selectedRange.length
+ };
+
+ unsigned int replacement[2] = {
+ replacementRange.location,
+ replacementRange.length
+ };
+
+ unichar text[[aString length]];
+ [[aString mutableString] getCharacters:text range:NSMakeRange(0, [aString length])];
+ attributedStringInfo segments = getSegments((NSAttributedString *)aString);
+ setMarkedText(text, selected, replacement, [aString length], segments);
+ mHasMarkedText = TRUE;
+ mMarkedTextLength = [aString length];
+ } else {
+ if (mHasMarkedText)
+ {
+ [self unmarkText];
+ }
+ }
+ }
+}
+
+- (void)commitCurrentPreedit
+{
+ if (mHasMarkedText)
+ {
+ if ([[self inputContext] respondsToSelector:@selector(commitEditing)])
+ {
+ [[self inputContext] commitEditing];
+ }
+ }
+}
+
+- (void)unmarkText
+{
+ [[self inputContext] discardMarkedText];
+ resetPreedit();
+ mHasMarkedText = FALSE;
+}
+
+// We don't support attributed strings.
+- (NSArray *)validAttributesForMarkedText
+{
+ return [NSArray array];
+}
+
+// See above.
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ return nil;
+}
+
+- (void)insertText:(id)insertString
+{
+ if (insertString != nil)
+ {
+ [self insertText:insertString replacementRange:NSMakeRange(0, [insertString length])];
+ }
+}
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ if (!mHasMarkedText)
+ {
+ for (NSInteger i = 0; i < [aString length]; i++)
+ {
+ callUnicodeCallback([aString characterAtIndex:i], mModifiers);
+ }
+ } else {
+ resetPreedit();
+ // We may never get this point since unmarkText may be called before insertText ever gets called once we submit our text.
+ // But just in case...
+
+ for (NSInteger i = 0; i < [aString length]; i++)
+ {
+ handleUnicodeCharacter([aString characterAtIndex:i]);
+ }
+ mHasMarkedText = FALSE;
+ }
+}
+
+- (void) insertNewline:(id)sender
+{
+ if (!(mModifiers & NSCommandKeyMask) &&
+ !(mModifiers & NSShiftKeyMask) &&
+ !(mModifiers & NSAlternateKeyMask))
+ {
+ callUnicodeCallback(13, 0);
+ } else {
+ callUnicodeCallback(13, mModifiers);
+ }
+}
+
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ return NSNotFound;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ float pos[4] = {0, 0, 0, 0};
+ getPreeditLocation(pos, mMarkedTextLength);
+ return NSMakeRect(pos[0], pos[1], pos[2], pos[3]);
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ if (aSelector == @selector(insertNewline:))
+ {
+ [self insertNewline:self];
+ }
+}
+
+- (BOOL)drawsVerticallyForCharacterAtIndex:(NSUInteger)charIndex
+{
+ return NO;
+}
+
+- (void) allowMarkedTextInput:(bool)allowed
+{
+ mMarkedTextAllowed = allowed;
+}
+
+@end
+
+@implementation LLUserInputWindow
+
+- (void) close
+{
+ [self orderOut:self];
+}
+
+@end
+
+@implementation LLNonInlineTextView
+
+- (void) setGLView:(LLOpenGLView *)view
+{
+ glview = view;
+}
+
+- (void) insertText:(id)insertString
+{
+ [[self inputContext] discardMarkedText];
+ [self setString:@""];
+ [_window orderOut:_window];
+ [self insertText:insertString replacementRange:NSMakeRange(0, [insertString length])];
+}
+
+- (void) insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ [glview insertText:aString replacementRange:replacementRange];
+}
+
+- (void) insertNewline:(id)sender
+{
+ [[self textStorage] setValue:@""];
+ [[self inputContext] discardMarkedText];
+ [self setString:@""];
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ if (aSelector == @selector(insertNewline:))
+ {
+ [self insertNewline:self];
+ }
+}
+
+@end
+
+@implementation LLNSWindow
+
+- (id) init
+{
+ return self;
+}
+
+- (NSPoint)convertToScreenFromLocalPoint:(NSPoint)point relativeToView:(NSView *)view
+{
+ NSScreen *currentScreen = [NSScreen currentScreenForMouseLocation];
+ if(currentScreen)
+ {
+ NSPoint windowPoint = [view convertPoint:point toView:nil];
+ NSPoint screenPoint = [[view window] convertBaseToScreen:windowPoint];
+ NSPoint flippedScreenPoint = [currentScreen flipPoint:screenPoint];
+ flippedScreenPoint.y += [currentScreen frame].origin.y;
+
+ return flippedScreenPoint;
+ }
+
+ return NSZeroPoint;
+}
+
+- (NSPoint)flipPoint:(NSPoint)aPoint
+{
+ return NSMakePoint(aPoint.x, self.frame.size.height - aPoint.y);
+}
+
+- (BOOL) becomeFirstResponder
+{
+ callFocus();
+ return true;
+}
+
+- (BOOL) resignFirstResponder
+{
+ callFocus();
+ return true;
+}
+
+- (void) close
+{
+ callQuitHandler();
+}
+
+@end
diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h
index 7893dedda4..914fc534fb 100755
--- a/indra/llwindow/llwindowmacosx-objc.h
+++ b/indra/llwindow/llwindowmacosx-objc.h
@@ -25,13 +25,119 @@
* $/LicenseInfo$
*/
+#include <map>
+#include <vector>
+
+typedef std::vector<std::pair<int, bool> > segment_t;
+
+typedef std::vector<int> segment_lengths;
+typedef std::vector<int> segment_standouts;
+
+struct attributedStringInfo {
+ segment_lengths seg_lengths;
+ segment_standouts seg_standouts;
+};
// This will actually hold an NSCursor*, but that type is only available in objective C.
typedef void *CursorRef;
+typedef void *NSWindowRef;
+typedef void *GLViewRef;
+
+// These are defined in llappviewermacosx.cpp.
+bool initViewer();
+void handleQuit();
+bool runMainLoop();
+void initMainLoop();
+void cleanupViewer();
/* Defined in llwindowmacosx-objc.mm: */
+int createNSApp(int argc, const char **argv);
void setupCocoa();
+bool pasteBoardAvailable();
+bool copyToPBoard(const unsigned short *str, unsigned int len);
+const unsigned short *copyFromPBoard();
CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY);
-OSErr releaseImageCursor(CursorRef ref);
-OSErr setImageCursor(CursorRef ref);
+short releaseImageCursor(CursorRef ref);
+short setImageCursor(CursorRef ref);
+void setArrowCursor();
+void setIBeamCursor();
+void setPointingHandCursor();
+void setCopyCursor();
+void setCrossCursor();
+void setNotAllowedCursor();
+void hideNSCursor();
+void showNSCursor();
+void hideNSCursorTillMove(bool hide);
+
+NSWindowRef createNSWindow(int x, int y, int width, int height);
+
+#include <OpenGL/OpenGL.h>
+GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync);
+void glSwapBuffers(void* context);
+CGLContextObj getCGLContextObj(GLViewRef view);
+unsigned long getVramSize(GLViewRef view);
+void getContentViewBounds(NSWindowRef window, float* bounds);
+void getWindowSize(NSWindowRef window, float* size);
+void setWindowSize(NSWindowRef window, int width, int height);
+void getCursorPos(NSWindowRef window, float* pos);
+void makeWindowOrderFront(NSWindowRef window);
+void convertScreenToWindow(NSWindowRef window, float *coord);
+void convertWindowToScreen(NSWindowRef window, float *coord);
+void convertScreenToView(NSWindowRef window, float *coord);
+void convertRectToScreen(NSWindowRef window, float *coord);
+void convertRectFromScreen(NSWindowRef window, float *coord);
+void setWindowPos(NSWindowRef window, float* pos);
+void closeWindow(NSWindowRef window);
+void removeGLView(GLViewRef view);
+void makeFirstResponder(NSWindowRef window, GLViewRef view);
+void setupInputWindow(NSWindowRef window, GLViewRef view);
+
+// These are all implemented in llwindowmacosx.cpp.
+// This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict)
+bool callKeyUp(unsigned short key, unsigned int mask);
+bool callKeyDown(unsigned short key, unsigned int mask);
+void callResetKeys();
+bool callUnicodeCallback(wchar_t character, unsigned int mask);
+void callRightMouseDown(float *pos, unsigned int mask);
+void callRightMouseUp(float *pos, unsigned int mask);
+void callLeftMouseDown(float *pos, unsigned int mask);
+void callLeftMouseUp(float *pos, unsigned int mask);
+void callDoubleClick(float *pos, unsigned int mask);
+void callResize(unsigned int width, unsigned int height);
+void callMouseMoved(float *pos, unsigned int mask);
+void callScrollMoved(float delta);
+void callMouseExit();
+void callWindowFocus();
+void callWindowUnfocus();
+void callDeltaUpdate(float *delta, unsigned int mask);
+void callMiddleMouseDown(float *pos, unsigned int mask);
+void callMiddleMouseUp(float *pos, unsigned int mask);
+void callFocus();
+void callFocusLost();
+void callModifier(unsigned int mask);
+void callQuitHandler();
+void commitCurrentPreedit(GLViewRef glView);
+
+#include <string>
+void callHandleDragEntered(std::string url);
+void callHandleDragExited(std::string url);
+void callHandleDragUpdated(std::string url);
+void callHandleDragDropped(std::string url);
+
+// LLPreeditor C bindings.
+std::basic_string<wchar_t> getPreeditString();
+void getPreeditSelectionRange(int *position, int *length);
+void getPreeditMarkedRange(int *position, int *length);
+bool handleUnicodeCharacter(wchar_t c);
+void updatePreeditor(unsigned short *str);
+void setPreeditMarkedRange(int position, int length);
+void resetPreedit();
+int wstring_length(const std::basic_string<wchar_t> & wstr, const int woffset, const int utf16_length, int *unaligned);
+void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments);
+void getPreeditLocation(float *location, unsigned int length);
+void allowDirectMarkedTextInput(bool allow, GLViewRef glView);
+
+NSWindowRef getMainAppWindow();
+GLViewRef getGLView();
+unsigned int getModifiers();
diff --git a/indra/llwindow/llwindowmacosx-objc.mm b/indra/llwindow/llwindowmacosx-objc.mm
index bebb537cd8..67b5279c0b 100755
--- a/indra/llwindow/llwindowmacosx-objc.mm
+++ b/indra/llwindow/llwindowmacosx-objc.mm
@@ -26,6 +26,10 @@
*/
#include <AppKit/AppKit.h>
+#include <Cocoa/Cocoa.h>
+#include "llopenglview-objc.h"
+#include "llwindowmacosx-objc.h"
+#include "llappdelegate-objc.h"
/*
* These functions are broken out into a separate file because the
@@ -34,7 +38,10 @@
* linden headers with any objective-C++ source.
*/
-#include "llwindowmacosx-objc.h"
+int createNSApp(int argc, const char *argv[])
+{
+ return NSApplicationMain(argc, argv);
+}
void setupCocoa()
{
@@ -48,15 +55,6 @@ void setupCocoa()
// ie. running './secondlife -set Language fr' would cause a pop-up saying can't open document 'fr'
// when init'ing the Cocoa App window.
[[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
-
- // This is a bit of voodoo taken from the Apple sample code "CarbonCocoa_PictureCursor":
- // http://developer.apple.com/samplecode/CarbonCocoa_PictureCursor/index.html
-
- // Needed for Carbon based applications which call into Cocoa
- NSApplicationLoad();
-
- // Must first call [[[NSWindow alloc] init] release] to get the NSWindow machinery set up so that NSCursor can use a window to cache the cursor image
- [[[NSWindow alloc] init] release];
[pool release];
@@ -64,6 +62,41 @@ void setupCocoa()
}
}
+bool copyToPBoard(const unsigned short *str, unsigned int len)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
+ NSPasteboard *pboard = [NSPasteboard generalPasteboard];
+ [pboard clearContents];
+
+ NSArray *contentsToPaste = [[NSArray alloc] initWithObjects:[NSString stringWithCharacters:str length:len], nil];
+ [pool release];
+ return [pboard writeObjects:contentsToPaste];
+}
+
+bool pasteBoardAvailable()
+{
+ NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
+ return [[NSPasteboard generalPasteboard] canReadObjectForClasses:classArray options:[NSDictionary dictionary]];
+}
+
+const unsigned short *copyFromPBoard()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
+ NSPasteboard *pboard = [NSPasteboard generalPasteboard];
+ NSArray *classArray = [NSArray arrayWithObject:[NSString class]];
+ NSString *str = NULL;
+ BOOL ok = [pboard canReadObjectForClasses:classArray options:[NSDictionary dictionary]];
+ if (ok)
+ {
+ NSArray *objToPaste = [pboard readObjectsForClasses:classArray options:[NSDictionary dictionary]];
+ str = [objToPaste objectAtIndex:0];
+ }
+ unichar* temp = (unichar*)calloc([str length], sizeof(unichar));
+ [str getCharacters:temp];
+ [pool release];
+ return temp;
+}
+
CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -83,6 +116,58 @@ CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY)
return (CursorRef)cursor;
}
+void setArrowCursor()
+{
+ NSCursor *cursor = [NSCursor arrowCursor];
+ [NSCursor unhide];
+ [cursor set];
+}
+
+void setIBeamCursor()
+{
+ NSCursor *cursor = [NSCursor IBeamCursor];
+ [cursor set];
+}
+
+void setPointingHandCursor()
+{
+ NSCursor *cursor = [NSCursor pointingHandCursor];
+ [cursor set];
+}
+
+void setCopyCursor()
+{
+ NSCursor *cursor = [NSCursor dragCopyCursor];
+ [cursor set];
+}
+
+void setCrossCursor()
+{
+ NSCursor *cursor = [NSCursor crosshairCursor];
+ [cursor set];
+}
+
+void setNotAllowedCursor()
+{
+ NSCursor *cursor = [NSCursor operationNotAllowedCursor];
+ [cursor set];
+}
+
+void hideNSCursor()
+{
+ [NSCursor hide];
+}
+
+void showNSCursor()
+{
+ [NSCursor unhide];
+}
+
+void hideNSCursorTillMove(bool hide)
+{
+ [NSCursor setHiddenUntilMouseMoves:hide];
+}
+
// This is currently unused, since we want all our cursors to persist for the life of the app, but I've included it for completeness.
OSErr releaseImageCursor(CursorRef ref)
{
@@ -118,3 +203,201 @@ OSErr setImageCursor(CursorRef ref)
return noErr;
}
+// Now for some unholy juggling between generic pointers and casting them to Obj-C objects!
+// Note: things can get a bit hairy from here. This is not for the faint of heart.
+
+NSWindowRef createNSWindow(int x, int y, int width, int height)
+{
+ LLNSWindow *window = [[LLNSWindow alloc]initWithContentRect:NSMakeRect(x, y, width, height)
+ styleMask:NSTitledWindowMask | NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTexturedBackgroundWindowMask backing:NSBackingStoreBuffered defer:NO];
+ [window makeKeyAndOrderFront:nil];
+ [window setAcceptsMouseMovedEvents:TRUE];
+ return window;
+}
+
+GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync)
+{
+ LLOpenGLView *glview = [[LLOpenGLView alloc]initWithFrame:[(LLNSWindow*)window frame] withSamples:samples andVsync:vsync];
+ [(LLNSWindow*)window setContentView:glview];
+ return glview;
+}
+
+void glSwapBuffers(void* context)
+{
+ [(NSOpenGLContext*)context flushBuffer];
+}
+
+CGLContextObj getCGLContextObj(GLViewRef view)
+{
+ return [(LLOpenGLView *)view getCGLContextObj];
+}
+
+CGLPixelFormatObj* getCGLPixelFormatObj(NSWindowRef window)
+{
+ LLOpenGLView *glview = [(LLNSWindow*)window contentView];
+ return [glview getCGLPixelFormatObj];
+}
+
+unsigned long getVramSize(GLViewRef view)
+{
+ return [(LLOpenGLView *)view getVramSize];
+}
+
+void getContentViewBounds(NSWindowRef window, float* bounds)
+{
+ bounds[0] = [[(LLNSWindow*)window contentView] bounds].origin.x;
+ bounds[1] = [[(LLNSWindow*)window contentView] bounds].origin.y;
+ bounds[2] = [[(LLNSWindow*)window contentView] bounds].size.width;
+ bounds[3] = [[(LLNSWindow*)window contentView] bounds].size.height;
+}
+
+void getWindowSize(NSWindowRef window, float* size)
+{
+ NSRect frame = [(LLNSWindow*)window frame];
+ size[0] = frame.origin.x;
+ size[1] = frame.origin.y;
+ size[2] = frame.size.width;
+ size[3] = frame.size.height;
+}
+
+void setWindowSize(NSWindowRef window, int width, int height)
+{
+ NSRect frame = [(LLNSWindow*)window frame];
+ frame.size.width = width;
+ frame.size.height = height;
+ [(LLNSWindow*)window setFrame:frame display:TRUE];
+}
+
+void setWindowPos(NSWindowRef window, float* pos)
+{
+ NSPoint point;
+ point.x = pos[0];
+ point.y = pos[1];
+ [(LLNSWindow*)window setFrameOrigin:point];
+}
+
+void getCursorPos(NSWindowRef window, float* pos)
+{
+ NSPoint mLoc;
+ mLoc = [(LLNSWindow*)window mouseLocationOutsideOfEventStream];
+ pos[0] = mLoc.x;
+ pos[1] = mLoc.y;
+}
+
+void makeWindowOrderFront(NSWindowRef window)
+{
+ [(LLNSWindow*)window makeKeyAndOrderFront:nil];
+}
+
+void convertScreenToWindow(NSWindowRef window, float *coord)
+{
+ NSRect point;
+ point.origin.x = coord[0];
+ point.origin.y = coord[1];
+ point = [(LLNSWindow*)window convertRectFromScreen:point];
+ coord[0] = point.origin.x;
+ coord[1] = point.origin.y;
+}
+
+void convertRectToScreen(NSWindowRef window, float *coord)
+{
+ NSRect point;
+ point.origin.x = coord[0];
+ point.origin.y = coord[1];
+ point.size.width = coord[2];
+ point.size.height = coord[3];
+
+ point = [(LLNSWindow*)window convertRectToScreen:point];
+
+ coord[0] = point.origin.x;
+ coord[1] = point.origin.y;
+ coord[2] = point.size.width;
+ coord[3] = point.size.height;
+}
+
+void convertRectFromScreen(NSWindowRef window, float *coord)
+{
+ NSRect point;
+ point.origin.x = coord[0];
+ point.origin.y = coord[1];
+ point.size.width = coord[2];
+ point.size.height = coord[3];
+
+ point = [(LLNSWindow*)window convertRectFromScreen:point];
+
+ coord[0] = point.origin.x;
+ coord[1] = point.origin.y;
+ coord[2] = point.size.width;
+ coord[3] = point.size.height;
+}
+
+void convertScreenToView(NSWindowRef window, float *coord)
+{
+ NSRect point;
+ point.origin.x = coord[0];
+ point.origin.y = coord[1];
+ point.origin = [(LLNSWindow*)window convertScreenToBase:point.origin];
+ point.origin = [[(LLNSWindow*)window contentView] convertPoint:point.origin fromView:nil];
+}
+
+void convertWindowToScreen(NSWindowRef window, float *coord)
+{
+ NSPoint point;
+ point.x = coord[0];
+ point.y = coord[1];
+ point = [(LLNSWindow*)window convertToScreenFromLocalPoint:point relativeToView:[(LLNSWindow*)window contentView]];
+ coord[0] = point.x;
+ coord[1] = point.y;
+}
+
+void closeWindow(NSWindowRef window)
+{
+ [(LLNSWindow*)window close];
+ [(LLNSWindow*)window release];
+}
+
+void removeGLView(GLViewRef view)
+{
+ [(LLOpenGLView*)view removeFromSuperview];
+ [(LLOpenGLView*)view release];
+}
+
+void setupInputWindow(NSWindowRef window, GLViewRef glview)
+{
+ [[(LLAppDelegate*)[NSApp delegate] inputView] setGLView:(LLOpenGLView*)glview];
+}
+
+void commitCurrentPreedit(GLViewRef glView)
+{
+ [(LLOpenGLView*)glView commitCurrentPreedit];
+}
+
+void allowDirectMarkedTextInput(bool allow, GLViewRef glView)
+{
+ [(LLOpenGLView*)glView allowMarkedTextInput:allow];
+}
+
+NSWindowRef getMainAppWindow()
+{
+ LLNSWindow *winRef = [(LLAppDelegate*)[[NSApplication sharedApplication] delegate] window];
+
+ [winRef setAcceptsMouseMovedEvents:TRUE];
+ return winRef;
+}
+
+void makeFirstResponder(NSWindowRef window, GLViewRef view)
+{
+ [(LLNSWindow*)window makeFirstResponder:(LLOpenGLView*)view];
+}
+
+/*
+GLViewRef getGLView()
+{
+ return [(LLAppDelegate*)[[NSApplication sharedApplication] delegate] glview];
+}
+*/
+
+unsigned int getModifiers()
+{
+ return [NSEvent modifierFlags];
+}
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 97637c937f..737ecba368 100755
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -30,7 +30,6 @@
#include "llkeyboardmacosx.h"
#include "llwindowcallbacks.h"
-#include "llwindowmacosx-objc.h"
#include "llpreeditor.h"
#include "llerror.h"
@@ -39,8 +38,8 @@
#include "lldir.h"
#include "indra_constants.h"
-#include <Carbon/Carbon.h>
#include <OpenGL/OpenGL.h>
+#include <CoreServices/CoreServices.h>
extern BOOL gDebugWindowProc;
@@ -58,7 +57,6 @@ const S32 MAX_NUM_RESOLUTIONS = 32;
//
BOOL LLWindowMacOSX::sUseMultGL = FALSE;
-WindowRef LLWindowMacOSX::sMediaWindow = NULL;
// Cross-platform bits:
@@ -98,105 +96,9 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card)
// We may want to base this on the setting of _DEBUG...
#define CAPTURE_ALL_DISPLAYS 0
-static double getDictDouble (CFDictionaryRef refDict, CFStringRef key);
+//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key);
static long getDictLong (CFDictionaryRef refDict, CFStringRef key);
-
-
-
-// CarbonEvents we're interested in.
-static EventTypeSpec WindowHandlerEventList[] =
-{
- // Window-related events
- { kEventClassWindow, kEventWindowActivated },
- { kEventClassWindow, kEventWindowDeactivated },
- { kEventClassWindow, kEventWindowShown },
- { kEventClassWindow, kEventWindowHidden },
- { kEventClassWindow, kEventWindowCollapsed },
- { kEventClassWindow, kEventWindowExpanded },
- { kEventClassWindow, kEventWindowGetClickActivation },
- { kEventClassWindow, kEventWindowClose },
- { kEventClassWindow, kEventWindowBoundsChanging },
- { kEventClassWindow, kEventWindowBoundsChanged },
- { kEventClassWindow, kEventWindowGetIdealSize },
-
- // Mouse events
- { kEventClassMouse, kEventMouseDown },
- { kEventClassMouse, kEventMouseUp },
- { kEventClassMouse, kEventMouseDragged },
- { kEventClassMouse, kEventMouseWheelMoved },
- { kEventClassMouse, kEventMouseMoved },
-
- // Keyboard events
- // No longer handle raw key down events directly.
- // When text input events come in, extract the raw key events from them and process at that point.
- // This allows input methods to eat keystrokes the way they're supposed to.
-// { kEventClassKeyboard, kEventRawKeyDown },
-// { kEventClassKeyboard, kEventRawKeyRepeat },
- { kEventClassKeyboard, kEventRawKeyUp },
- { kEventClassKeyboard, kEventRawKeyModifiersChanged },
-
- // Text input events
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
- { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
- { kEventClassTextInput, kEventTextInputOffsetToPos },
- { kEventClassTextInput, kEventTextInputPosToOffset },
- { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
- { kEventClassTextInput, kEventTextInputGetSelectedText },
- { kEventClassTextInput, kEventTextInputFilterText },
-
- // TSM Document Access events (advanced input method support)
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
-};
-
-static EventTypeSpec GlobalHandlerEventList[] =
-{
- // Mouse events
- { kEventClassMouse, kEventMouseDown },
- { kEventClassMouse, kEventMouseUp },
- { kEventClassMouse, kEventMouseDragged },
- { kEventClassMouse, kEventMouseWheelMoved },
- { kEventClassMouse, kEventMouseMoved },
-
- // Keyboard events
- // No longer handle raw key down events directly.
- // When text input events come in, extract the raw key events from them and process at that point.
- // This allows input methods to eat keystrokes the way they're supposed to.
-// { kEventClassKeyboard, kEventRawKeyDown },
-// { kEventClassKeyboard, kEventRawKeyRepeat },
- { kEventClassKeyboard, kEventRawKeyUp },
- { kEventClassKeyboard, kEventRawKeyModifiersChanged },
-
- // Text input events
- { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
- { kEventClassTextInput, kEventTextInputOffsetToPos },
- { kEventClassTextInput, kEventTextInputPosToOffset },
- { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
- { kEventClassTextInput, kEventTextInputGetSelectedText },
- { kEventClassTextInput, kEventTextInputFilterText },
-
- // TSM Document Access events (advanced input method support)
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
-};
-
-static EventTypeSpec CommandHandlerEventList[] =
-{
- { kEventClassCommand, kEventCommandProcess }
-};
-
// MBW -- HACK ALERT
// On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode.
// The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these
@@ -204,8 +106,6 @@ static EventTypeSpec CommandHandlerEventList[] =
// This assumes that there will be only one object of this class at any time. Hopefully this is true.
static LLWindowMacOSX *gWindowImplementation = NULL;
-
-
LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
const std::string& title, const std::string& name, S32 x, S32 y, S32 width,
S32 height, U32 flags,
@@ -233,8 +133,6 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
mContext = NULL;
mPixelFormat = NULL;
mDisplay = CGMainDisplayID();
- mOldDisplayMode = NULL;
- mTimer = NULL;
mSimulatedRightClick = FALSE;
mLastModifiers = 0;
mHandsOffEvents = FALSE;
@@ -246,12 +144,8 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
mOverrideAspectRatio = 0.f;
mMaximized = FALSE;
mMinimized = FALSE;
- mTSMDocument = NULL; // Just in case.
mLanguageTextInputAllowed = FALSE;
- mTSMScriptCode = 0;
- mTSMLangCode = 0;
mPreeditor = NULL;
- mRawKeyEvent = NULL;
mFSAASamples = fsaa_samples;
mForceRebuild = FALSE;
@@ -263,43 +157,23 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay);
// Stash the window title
- strcpy((char*)mWindowTitle + 1, title.c_str()); /* Flawfinder: ignore */
- mWindowTitle[0] = title.length();
-
- mEventHandlerUPP = NewEventHandlerUPP(staticEventHandler);
- mMoveEventCampartorUPP = NewEventComparatorUPP(staticMoveEventComparator);
- mGlobalHandlerRef = NULL;
- mWindowHandlerRef = NULL;
+ mWindowTitle = title;
+ //mWindowTitle[0] = title.length();
mDragOverrideCursor = -1;
- // We're not clipping yet
- SetRect( &mOldMouseClip, 0, 0, 0, 0 );
-
// Set up global event handlers (the fullscreen case needs this)
- InstallStandardEventHandler(GetApplicationEventTarget());
+ //InstallStandardEventHandler(GetApplicationEventTarget());
// Stash an object pointer for OSMessageBox()
gWindowImplementation = this;
-
// Create the GL context and set it up for windowed or fullscreen, as appropriate.
+ LL_INFOS("Window") << "Creating context..." << LL_ENDL;
if(createContext(x, y, width, height, 32, fullscreen, disable_vsync))
{
if(mWindow != NULL)
{
- // MBW -- XXX -- I think we can now do this here?
- // Constrain the window to the screen it's mostly on, resizing if necessary.
- ConstrainWindowToScreen(
- mWindow,
- kWindowStructureRgn,
- kWindowConstrainMayResize |
- // kWindowConstrainStandardOptions |
- 0,
- NULL,
- NULL);
-
- MacShowWindow(mWindow);
- BringToFront(mWindow);
+ makeWindowOrderFront(mWindow);
}
if (!gGLManager.initGL())
@@ -317,465 +191,378 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks,
//start with arrow cursor
initCursors();
setCursor( UI_CURSOR_ARROW );
+
+ allowLanguageTextInput(NULL, FALSE);
}
mCallbacks = callbacks;
stop_glerror();
+
+
}
-BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
+// These functions are used as wrappers for our internal event handling callbacks.
+// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow.
+
+bool callKeyUp(unsigned short key, unsigned int mask)
{
- OSStatus err;
- BOOL glNeedsInit = FALSE;
+ return gKeyboard->handleKeyUp(key, mask);
+}
- if(mGlobalHandlerRef == NULL)
- {
- InstallApplicationEventHandler(mEventHandlerUPP, GetEventTypeCount (CommandHandlerEventList), CommandHandlerEventList, (void*)this, &mGlobalHandlerRef);
- }
+bool callKeyDown(unsigned short key, unsigned int mask)
+{
+ return gKeyboard->handleKeyDown(key, mask);
+}
- mFullscreen = fullscreen;
+void callResetKeys()
+{
+ gKeyboard->resetKeys();
+}
- if (mFullscreen && (mOldDisplayMode == NULL))
- {
- LL_INFOS("Window") << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL;
+bool callUnicodeCallback(wchar_t character, unsigned int mask)
+{
+ return gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask);
+}
- // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays. Plan accordingly.
- double refresh = getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate);
+void callFocus()
+{
+ if (gWindowImplementation)
+ {
+ gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation);
+ }
+}
- // If the requested width or height is 0, find the best default for the monitor.
- if((width == 0) || (height == 0))
- {
- // Scan through the list of modes, looking for one which has:
- // height between 700 and 800
- // aspect ratio closest to the user's original mode
- S32 resolutionCount = 0;
- LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount);
+void callFocusLost()
+{
+ gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation);
+}
- if(resolutionList != NULL)
- {
- F32 closestAspect = 0;
- U32 closestHeight = 0;
- U32 closestWidth = 0;
- int i;
+void callRightMouseDown(float *pos, MASK mask)
+{
+ if (gWindowImplementation->allowsLanguageInput())
+ {
+ gWindowImplementation->interruptLanguageTextInput();
+ }
+
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+}
- LL_DEBUGS("Window") << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL;
+void callRightMouseUp(float *pos, MASK mask)
+{
+ if (gWindowImplementation->allowsLanguageInput())
+ {
+ gWindowImplementation->interruptLanguageTextInput();
+ }
+
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+}
- for(i=0; i < resolutionCount; i++)
- {
- F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight;
+void callLeftMouseDown(float *pos, MASK mask)
+{
+ if (gWindowImplementation->allowsLanguageInput())
+ {
+ gWindowImplementation->interruptLanguageTextInput();
+ }
+
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+}
- LL_DEBUGS("Window") << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL;
+void callLeftMouseUp(float *pos, MASK mask)
+{
+ if (gWindowImplementation->allowsLanguageInput())
+ {
+ gWindowImplementation->interruptLanguageTextInput();
+ }
+
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+
+}
- if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) &&
- (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio)))
- {
- LL_DEBUGS("Window") << " (new closest mode) " << LL_ENDL;
+void callDoubleClick(float *pos, MASK mask)
+{
+ if (gWindowImplementation->allowsLanguageInput())
+ {
+ gWindowImplementation->interruptLanguageTextInput();
+ }
+
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+}
- // This is the closest mode we've seen yet.
- closestWidth = resolutionList[i].mWidth;
- closestHeight = resolutionList[i].mHeight;
- closestAspect = aspect;
- }
- }
+void callResize(unsigned int width, unsigned int height)
+{
+ if (gWindowImplementation != NULL)
+ {
+ gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height);
+ }
+}
- width = closestWidth;
- height = closestHeight;
- }
- }
+void callMouseMoved(float *pos, MASK mask)
+{
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ float deltas[2];
+ gWindowImplementation->getMouseDeltas(deltas);
+ outCoords.mX += deltas[0];
+ outCoords.mY += deltas[1];
+ gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE));
+ gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0);
+}
- if((width == 0) || (height == 0))
- {
- // Mode search failed for some reason. Use the old-school default.
- width = 1024;
- height = 768;
- }
+void callScrollMoved(float delta)
+{
+ gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, delta);
+}
- if (true)
- {
- // Fullscreen support
- CFDictionaryRef refDisplayMode = 0;
- boolean_t exactMatch = false;
-
-#if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- CGCaptureAllDisplays ();
-#else
- // Capture only the main display (useful for debugging)
- CGDisplayCapture (mDisplay);
-#endif
+void callMouseExit()
+{
+ gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation);
+}
- // Switch the display to the desired resolution and refresh
- refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate(
- mDisplay,
- BITS_PER_PIXEL,
- width,
- height,
- refresh,
- &exactMatch);
+void callWindowFocus()
+{
+ gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation);
+}
- if (refDisplayMode)
- {
- LL_DEBUGS("Window") << "createContext: switching display resolution" << LL_ENDL;
- mOldDisplayMode = CGDisplayCurrentMode (mDisplay);
- CGDisplaySwitchToMode (mDisplay, refDisplayMode);
- // CFRelease(refDisplayMode);
+void callWindowUnfocus()
+{
+ gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation);
+}
- AddEventTypesToHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList);
- }
+void callDeltaUpdate(float *delta, MASK mask)
+{
+ gWindowImplementation->updateMouseDeltas(delta);
+}
+void callMiddleMouseDown(float *pos, MASK mask)
+{
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ float deltas[2];
+ gWindowImplementation->getMouseDeltas(deltas);
+ outCoords.mX += deltas[0];
+ outCoords.mY += deltas[1];
+ gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask);
+}
- mFullscreen = TRUE;
- mFullscreenWidth = CGDisplayPixelsWide(mDisplay);
- mFullscreenHeight = CGDisplayPixelsHigh(mDisplay);
- mFullscreenBits = CGDisplayBitsPerPixel(mDisplay);
- mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate));
+void callMiddleMouseUp(float *pos, MASK mask)
+{
+ LLCoordGL outCoords;
+ outCoords.mX = llround(pos[0]);
+ outCoords.mY = llround(pos[1]);
+ float deltas[2];
+ gWindowImplementation->getMouseDeltas(deltas);
+ outCoords.mX += deltas[0];
+ outCoords.mY += deltas[1];
+ gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask);
+}
- LL_INFOS("Window") << "Running at " << mFullscreenWidth
- << "x" << mFullscreenHeight
- << "x" << mFullscreenBits
- << " @ " << mFullscreenRefresh
- << LL_ENDL;
- }
- else
- {
- // No fullscreen support
- mFullscreen = FALSE;
- mFullscreenWidth = -1;
- mFullscreenHeight = -1;
- mFullscreenBits = -1;
- mFullscreenRefresh = -1;
-
- std::string error= llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height);
- OSMessageBox(error, "Error", OSMB_OK);
- }
- }
+void callModifier(MASK mask)
+{
+ gKeyboard->handleModifier(mask);
+}
- if(!mFullscreen && (mWindow == NULL))
- {
- //int displayWidth = CGDisplayPixelsWide(mDisplay);
- //int displayHeight = CGDisplayPixelsHigh(mDisplay);
- //const int menuBarPlusTitleBar = 44; // Ugly magic number.
+void callHandleDragEntered(std::string url)
+{
+ gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING);
+}
- LL_DEBUGS("Window") << "createContext: creating window" << LL_ENDL;
+void callHandleDragExited(std::string url)
+{
+ gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING);
+}
- mPreviousWindowRect.left = (long) x;
- mPreviousWindowRect.right = (long) x + width;
- mPreviousWindowRect.top = (long) y;
- mPreviousWindowRect.bottom = (long) y + height;
+void callHandleDragUpdated(std::string url)
+{
+ gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK);
+}
- //-----------------------------------------------------------------------
- // Create the window
- //-----------------------------------------------------------------------
- mWindow = NewCWindow(
- NULL,
- &mPreviousWindowRect,
- mWindowTitle,
- false, // Create the window invisible. Whoever calls createContext() should show it after any moving/resizing.
- // noGrowDocProc, // Window with no grow box and no zoom box
- zoomDocProc, // Window with a grow box and a zoom box
- // zoomNoGrow, // Window with a zoom box but no grow box
- kFirstWindowOfClass,
- true,
- (long)this);
+void callHandleDragDropped(std::string url)
+{
+ gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED);
+}
- if (!mWindow)
+void callQuitHandler()
+{
+ if (gWindowImplementation)
+ {
+ if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
{
- setupFailure("Window creation error", "Error", OSMB_OK);
- return FALSE;
+ gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation);
}
-
- // Turn on live resize.
- // For this to work correctly, we need to be able to call LLViewerWindow::draw from
- // the event handler for kEventWindowBoundsChanged. It's not clear that we have access from here.
- // err = ChangeWindowAttributes(mWindow, kWindowLiveResizeAttribute, 0);
-
- // Set up window event handlers (some window-related events ONLY go to window handlers.)
- InstallStandardEventHandler(GetWindowEventTarget(mWindow));
- InstallWindowEventHandler(mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler
-#if LL_OS_DRAGDROP_ENABLED
- InstallTrackingHandler( dragTrackingHandler, mWindow, (void*)this );
- InstallReceiveHandler( dragReceiveHandler, mWindow, (void*)this );
-#endif // LL_OS_DRAGDROP_ENABLED
}
+}
+void getPreeditSelectionRange(int *position, int *length)
+{
+ if (gWindowImplementation->getPreeditor())
{
- // Create and initialize our TSM document for language text input.
- // If an error occured, we can do nothing better than simply ignore it.
- // mTSMDocument will be kept NULL in case.
- if (mTSMDocument)
- {
- DeactivateTSMDocument(mTSMDocument);
- DeleteTSMDocument(mTSMDocument);
- mTSMDocument = NULL;
- }
- static InterfaceTypeList types = { kUnicodeDocument };
- err = NewTSMDocument(1, types, &mTSMDocument, 0);
- if (err != noErr)
- {
- LL_WARNS("Window") << "createContext: couldn't create a TSMDocument (" << err << ")" << LL_ENDL;
- }
- if (mTSMDocument)
- {
- ActivateTSMDocument(mTSMDocument);
- allowLanguageTextInput(NULL, FALSE);
- }
+ gWindowImplementation->getPreeditor()->getSelectionRange(position, length);
}
+}
- if(mContext == NULL)
+void getPreeditMarkedRange(int *position, int *length)
+{
+ if (gWindowImplementation->getPreeditor())
{
- AGLRendererInfo rendererInfo = NULL;
-
- //-----------------------------------------------------------------------
- // Create GL drawing context
- //-----------------------------------------------------------------------
-
- if(mPixelFormat == NULL)
- {
- if(mFullscreen)
- {
- GLint fullscreenAttrib[] =
- {
- AGL_RGBA,
- AGL_FULLSCREEN,
- AGL_NO_RECOVERY,
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
- };
-
- LL_DEBUGS("Window") << "createContext: creating fullscreen pixelformat" << LL_ENDL;
-
- GDHandle gdhDisplay = NULL;
- err = DMGetGDeviceByDisplayID ((DisplayIDType)mDisplay, &gdhDisplay, false);
-
- mPixelFormat = aglChoosePixelFormat(&gdhDisplay, 1, fullscreenAttrib);
- rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1);
- }
- else
- {
- // NOTE from Leslie:
- //
- // AGL_NO_RECOVERY, when combined with AGL_ACCELERATED prevents software rendering
- // fallback which means we won't hvae shaders that compile and link but then don't
- // work. The drawback is that our shader compilation will be a bit more finicky though.
-
- GLint windowedAttrib[] =
- {
- AGL_RGBA,
- AGL_NO_RECOVERY,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
- };
-
- LL_DEBUGS("Window") << "createContext: creating windowed pixelformat" << LL_ENDL;
-
- mPixelFormat = aglChoosePixelFormat(NULL, 0, windowedAttrib);
-
- GDHandle gdhDisplay = GetMainDevice();
- rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1);
- }
-
- // May want to get the real error text like this:
- // (char *) aglErrorString(aglGetError());
-
- if(aglGetError() != AGL_NO_ERROR)
- {
- setupFailure("Can't find suitable pixel format", "Error", OSMB_OK);
- return FALSE;
- }
- }
-
- if(mPixelFormat)
- {
- LL_DEBUGS("Window") << "createContext: creating GL context" << LL_ENDL;
- mContext = aglCreateContext(mPixelFormat, NULL);
- }
-
- if(mContext == NULL)
- {
- setupFailure("Can't make GL context", "Error", OSMB_OK);
- return FALSE;
- }
-
- gGLManager.mVRAM = 0;
-
- if(rendererInfo != NULL)
- {
- GLint result;
-
- if(aglDescribeRenderer(rendererInfo, AGL_VIDEO_MEMORY, &result))
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) returned " << result << llendl;
- gGLManager.mVRAM = result / (1024 * 1024);
- }
- else
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) failed." << llendl;
- }
-
- // This could be useful at some point, if it takes into account the memory already used by screen buffers, etc...
- if(aglDescribeRenderer(rendererInfo, AGL_TEXTURE_MEMORY, &result))
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) returned " << result << llendl;
- }
- else
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) failed." << llendl;
- }
-
- aglDestroyRendererInfo(rendererInfo);
- }
-
- // Since we just created the context, it needs to be set up.
- glNeedsInit = TRUE;
+ gWindowImplementation->getPreeditor()->getPreeditRange(position, length);
}
+}
- // Hook up the context to a drawable
- if (mFullscreen && (mOldDisplayMode != NULL))
+void setPreeditMarkedRange(int position, int length)
+{
+ if (gWindowImplementation->getPreeditor())
{
- // We successfully captured the display. Use a fullscreen drawable
-
- LL_DEBUGS("Window") << "createContext: attaching fullscreen drawable" << LL_ENDL;
-
-#if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- aglDisable (mContext, AGL_FS_CAPTURE_SINGLE);
-#else
- // Capture only the main display (useful for debugging)
- aglEnable (mContext, AGL_FS_CAPTURE_SINGLE);
-#endif
-
- if (!aglSetFullScreen (mContext, 0, 0, 0, 0))
- {
- setupFailure("Can't set GL fullscreen", "Error", OSMB_OK);
- return FALSE;
- }
+ gWindowImplementation->getPreeditor()->markAsPreedit(position, length);
}
- else if(!mFullscreen && (mWindow != NULL))
- {
- LL_DEBUGS("Window") << "createContext: attaching windowed drawable" << LL_ENDL;
+}
- // We created a window. Use it as the drawable.
- if(!aglSetDrawable(mContext, GetWindowPort (mWindow)))
- {
- setupFailure("Can't set GL drawable", "Error", OSMB_OK);
- return FALSE;
- }
- }
- else
+bool handleUnicodeCharacter(wchar_t c)
+{
+ bool success = false;
+ if (gWindowImplementation->getPreeditor())
{
- setupFailure("Can't get fullscreen or windowed drawable.", "Error", OSMB_OK);
- return FALSE;
+ success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c);
}
+
+ return success;
+}
- if(mContext != NULL)
+void resetPreedit()
+{
+ if (gWindowImplementation->getPreeditor())
{
- LL_DEBUGS("Window") << "createContext: setting current context" << LL_ENDL;
+ gWindowImplementation->getPreeditor()->resetPreedit();
+ }
+}
- if (!aglSetCurrentContext(mContext))
+// For reasons of convenience, handle IME updates here.
+// This largely mirrors the old implementation, only sans the carbon parameters.
+void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments)
+{
+ if (gWindowImplementation->getPreeditor())
+ {
+ LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
+ preeditor->resetPreedit();
+ // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter.
+ if (replacementRange[0] < replacementRange[1])
{
- setupFailure("Can't activate GL rendering context", "Error", OSMB_OK);
- return FALSE;
+ const LLWString& text = preeditor->getPreeditString();
+ const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]);
+ const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]);
+ preeditor->markAsPreedit(location, length);
}
+
+ LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len));
+
+ S32 caret_position = fix_str.length();
+
+ preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position);
}
+}
- if(glNeedsInit)
+void getPreeditLocation(float *location, unsigned int length)
+{
+ if (gWindowImplementation->getPreeditor())
{
- // Check for some explicitly unsupported cards.
- const char* RENDERER = (const char*) glGetString(GL_RENDERER);
-
- const char* CARD_LIST[] =
- { "RAGE 128",
- "RIVA TNT2",
- "Intel 810",
- "3Dfx/Voodoo3",
- "Radeon 7000",
- "Radeon 7200",
- "Radeon 7500",
- "Radeon DDR",
- "Radeon VE",
- "GDI Generic" };
- const S32 CARD_COUNT = LL_ARRAY_SIZE(CARD_LIST);
-
- // Future candidates:
- // ProSavage/Twister
- // SuperSavage
+ LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
+ LLCoordGL coord;
+ LLCoordScreen screen;
+ LLRect rect;
+
+ preeditor->getPreeditLocation(length, &coord, &rect, NULL);
+
+ float c[4] = {coord.mX, coord.mY, 0, 0};
+
+ convertRectToScreen(gWindowImplementation->getWindow(), c);
+
+ location[0] = c[0];
+ location[1] = c[1];
+ }
+}
- S32 i;
- for (i = 0; i < CARD_COUNT; i++)
+void LLWindowMacOSX::updateMouseDeltas(float* deltas)
+{
+ if (mCursorDecoupled)
+ {
+ mCursorLastEventDeltaX = llround(deltas[0]);
+ mCursorLastEventDeltaY = llround(-deltas[1]);
+
+ if (mCursorIgnoreNextDelta)
{
- if (check_for_card(RENDERER, CARD_LIST[i]))
- {
- close();
- return FALSE;
- }
+ mCursorLastEventDeltaX = 0;
+ mCursorLastEventDeltaY = 0;
+ mCursorIgnoreNextDelta = FALSE;
}
+ } else {
+ mCursorLastEventDeltaX = 0;
+ mCursorLastEventDeltaY = 0;
}
+}
+
+void LLWindowMacOSX::getMouseDeltas(float* delta)
+{
+ delta[0] = mCursorLastEventDeltaX;
+ delta[1] = mCursorLastEventDeltaY;
+}
- GLint colorBits, alphaBits, depthBits, stencilBits;
+BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
+{
+ BOOL glNeedsInit = FALSE;
- if( !aglDescribePixelFormat(mPixelFormat, AGL_BUFFER_SIZE, &colorBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_ALPHA_SIZE, &alphaBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_DEPTH_SIZE, &depthBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_STENCIL_SIZE, &stencilBits))
+ mFullscreen = fullscreen;
+
+ if (mWindow == NULL)
{
- close();
- setupFailure("Can't get pixel format description", "Error", OSMB_OK);
- return FALSE;
+ LL_INFOS("Window") << "Creating window..." << LL_ENDL;
+ mWindow = getMainAppWindow();
}
- LL_INFOS("GLInit") << "GL buffer: Color Bits " << S32(colorBits)
- << " Alpha Bits " << S32(alphaBits)
- << " Depth Bits " << S32(depthBits)
- << " Stencil Bits" << S32(stencilBits)
- << LL_ENDL;
-
- if (colorBits < 32)
+ if(mContext == NULL)
{
- close();
- setupFailure(
- "Second Life requires True Color (32-bit) to run in a window.\n"
- "Please go to Control Panels -> Display -> Settings and\n"
- "set the screen to 32-bit color.\n"
- "Alternately, if you choose to run fullscreen, Second Life\n"
- "will automatically adjust the screen each time it runs.",
- "Error",
- OSMB_OK);
- return FALSE;
+ LL_INFOS("Window") << "Creating GL view..." << LL_ENDL;
+ // Our OpenGL view is already defined within SecondLife.xib.
+ // Get the view instead.
+ mGLView = createOpenGLView(mWindow, mFSAASamples, !disable_vsync);
+ mContext = getCGLContextObj(mGLView);
+
+ // Since we just created the context, it needs to be set up.
+ glNeedsInit = TRUE;
+
+ gGLManager.mVRAM = getVramSize(mGLView);
}
+
+ // This sets up our view to recieve text from our non-inline text input window.
+ setupInputWindow(mWindow, mGLView);
+
+ // Hook up the context to a drawable
- if (alphaBits < 8)
+ if(mContext != NULL)
{
- close();
- setupFailure(
- "Second Life is unable to run because it can't get an 8 bit alpha\n"
- "channel. Usually this is due to video card driver issues.\n"
- "Please make sure you have the latest video card drivers installed.\n"
- "Also be sure your monitor is set to True Color (32-bit) in\n"
- "Control Panels -> Display -> Settings.\n"
- "If you continue to receive this message, contact customer service.",
- "Error",
- OSMB_OK);
- return FALSE;
+
+
+ U32 err = CGLSetCurrentContext(mContext);
+ if (err != kCGLNoError)
+ {
+ setupFailure("Can't activate GL rendering context", "Error", OSMB_OK);
+ return FALSE;
+ }
}
// Disable vertical sync for swap
@@ -790,7 +577,8 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
LL_DEBUGS("GLinit") << "Keeping vertical sync" << LL_ENDL;
frames_per_swap = 1;
}
- aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap);
+
+ CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap);
//enable multi-threaded OpenGL
if (sUseMultGL)
@@ -809,109 +597,18 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits
LL_DEBUGS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL;
}
}
-
+ LL_INFOS("Window") << "Completed context creation." << LL_ENDL;
+ makeFirstResponder(mWindow, mGLView);
// Don't need to get the current gamma, since there's a call that restores it to the system defaults.
return TRUE;
}
-// changing fullscreen resolution, or switching between windowed and fullscreen mode.
+// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop.
+// This makes this method obsolete.
BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
{
- BOOL needsRebuild = FALSE;
- BOOL result = true;
-
- if(fullscreen)
- {
- if(mFullscreen)
- {
- // Switching resolutions in fullscreen mode. Don't need to rebuild for this.
- // Fullscreen support
- CFDictionaryRef refDisplayMode = 0;
- boolean_t exactMatch = false;
-
- // Switch the display to the desired resolution and refresh
- refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate(
- mDisplay,
- BITS_PER_PIXEL,
- size.mX,
- size.mY,
- getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate),
- &exactMatch);
-
- if (refDisplayMode)
- {
- CGDisplaySwitchToMode (mDisplay, refDisplayMode);
- // CFRelease(refDisplayMode);
- }
-
- mFullscreenWidth = CGDisplayPixelsWide(mDisplay);
- mFullscreenHeight = CGDisplayPixelsHigh(mDisplay);
- mFullscreenBits = CGDisplayBitsPerPixel(mDisplay);
- mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate));
-
- LL_INFOS("Window") << "Switched resolution to " << mFullscreenWidth
- << "x" << mFullscreenHeight
- << "x" << mFullscreenBits
- << " @ " << mFullscreenRefresh
- << LL_ENDL;
-
- // Update the GL context to the new screen size
- if (!aglUpdateContext(mContext))
- {
- setupFailure("Can't set GL fullscreen", "Error", OSMB_OK);
- result = FALSE;
- }
- }
- else
- {
- // Switching from windowed to fullscreen
- needsRebuild = TRUE;
- }
- }
- else
- {
- if(mFullscreen)
- {
- // Switching from fullscreen to windowed
- needsRebuild = TRUE;
- }
- else
- {
- // Windowed to windowed -- not sure why we would be called like this. Just change the window size.
- // The bounds changed event handler will do the rest.
- if(mWindow != NULL)
- {
- ::SizeWindow(mWindow, size.mX, size.mY, true);
- }
- }
- }
-
- stop_glerror();
- if(needsRebuild || mForceRebuild)
- {
- mForceRebuild = FALSE;
- destroyContext();
- result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync);
- if (result)
- {
- if(mWindow != NULL)
- {
- MacShowWindow(mWindow);
- BringToFront(mWindow);
- }
-
- llverify(gGLManager.initGL());
-
- //start with arrow cursor
- initCursors();
- setCursor( UI_CURSOR_ARROW );
- }
- }
-
- stop_glerror();
-
- return result;
+ return FALSE;
}
void LLWindowMacOSX::destroyContext()
@@ -925,32 +622,7 @@ void LLWindowMacOSX::destroyContext()
if(mContext != NULL)
{
LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL;
-
- aglSetCurrentContext (NULL);
- aglSetDrawable(mContext, NULL);
- }
-
- // Make sure the display resolution gets restored
- if(mOldDisplayMode != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: restoring display resolution " << LL_ENDL;
-
- CGDisplaySwitchToMode (mDisplay, mOldDisplayMode);
-
-#if CAPTURE_ALL_DISPLAYS
- // Uncapture all displays (may want to do this for final build)
- CGReleaseAllDisplays ();
-#else
- // Uncapture only the main display (useful for debugging)
- CGDisplayRelease (mDisplay);
-#endif
-
- // CFRelease(mOldDisplayMode);
-
- mOldDisplayMode = NULL;
-
- // Remove the global event handlers the fullscreen case needed
- RemoveEventTypesFromHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList);
+ CGLSetCurrentContext(NULL);
}
// Clean up remaining GL state before blowing away window
@@ -959,49 +631,29 @@ void LLWindowMacOSX::destroyContext()
// Clean up the pixel format
if(mPixelFormat != NULL)
{
- LL_DEBUGS("Window") << "destroyContext: destroying pixel format " << LL_ENDL;
- aglDestroyPixelFormat(mPixelFormat);
+ CGLDestroyPixelFormat(mPixelFormat);
mPixelFormat = NULL;
}
- // Remove any Carbon Event handlers we installed
- if(mGlobalHandlerRef != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: removing global event handler" << LL_ENDL;
- RemoveEventHandler(mGlobalHandlerRef);
- mGlobalHandlerRef = NULL;
- }
-
- if(mWindowHandlerRef != NULL)
+ // Clean up the GL context
+ if(mContext != NULL)
{
- LL_DEBUGS("Window") << "destroyContext: removing window event handler" << LL_ENDL;
- RemoveEventHandler(mWindowHandlerRef);
- mWindowHandlerRef = NULL;
+ CGLDestroyContext(mContext);
}
-
- // Cleanup any TSM document we created.
- if(mTSMDocument != NULL)
+
+ // Destroy our LLOpenGLView
+ if(mGLView != NULL)
{
- LL_DEBUGS("Window") << "destroyContext: deleting TSM document" << LL_ENDL;
- DeactivateTSMDocument(mTSMDocument);
- DeleteTSMDocument(mTSMDocument);
- mTSMDocument = NULL;
+ removeGLView(mGLView);
+ mGLView = NULL;
}
-
+
// Close the window
if(mWindow != NULL)
{
- LL_DEBUGS("Window") << "destroyContext: disposing window" << LL_ENDL;
- DisposeWindow(mWindow);
- mWindow = NULL;
- }
-
- // Clean up the GL context
- if(mContext != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: destroying GL context" << LL_ENDL;
- aglDestroyContext(mContext);
- mContext = NULL;
+ NSWindowRef dead_window = mWindow;
+ mWindow = NULL;
+ closeWindow(dead_window);
}
}
@@ -1022,17 +674,11 @@ LLWindowMacOSX::~LLWindowMacOSX()
void LLWindowMacOSX::show()
{
- if(IsWindowCollapsed(mWindow))
- CollapseWindow(mWindow, false);
-
- MacShowWindow(mWindow);
- BringToFront(mWindow);
}
void LLWindowMacOSX::hide()
{
setMouseClipping(FALSE);
- HideWindow(mWindow);
}
//virtual
@@ -1040,7 +686,6 @@ void LLWindowMacOSX::minimize()
{
setMouseClipping(FALSE);
showCursor();
- CollapseWindow(mWindow, true);
}
//virtual
@@ -1086,7 +731,6 @@ BOOL LLWindowMacOSX::getVisible()
result = TRUE;
}if (mWindow)
{
- if(MacIsWindowVisible(mWindow))
result = TRUE;
}
@@ -1107,7 +751,6 @@ BOOL LLWindowMacOSX::maximize()
{
if (mWindow && !mMaximized)
{
- ZoomWindow(mWindow, inContent, true);
}
return mMaximized;
@@ -1125,53 +768,14 @@ void LLWindowMacOSX::gatherInput()
{
stopDockTileBounce();
}
-
- // Use the old-school version so we get AppleEvent handler dispatch and menuselect handling.
- // Anything that has an event handler will get processed inside WaitNextEvent, so we only need to handle
- // the odd stuff here.
- EventRecord evt;
- while(WaitNextEvent(everyEvent, &evt, 0, NULL))
- {
- // printf("WaitNextEvent returned true, event is %d.\n", evt.what);
- switch(evt.what)
- {
- case mouseDown:
- {
- short part;
- WindowRef window;
- long selectResult;
- part = FindWindow(evt.where, &window);
- switch ( part )
- {
- case inMenuBar:
- selectResult = MenuSelect(evt.where);
-
- HiliteMenu(0);
- break;
- }
- }
- break;
-
- case kHighLevelEvent:
- AEProcessAppleEvent (&evt);
- break;
-
- case updateEvt:
- // We shouldn't be getting these regularly (since our window will be buffered), but we need to handle them correctly...
- BeginUpdate((WindowRef)evt.message);
- EndUpdate((WindowRef)evt.message);
- break;
-
- }
- }
updateCursor();
}
BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position)
{
- Rect window_rect;
- OSStatus err = -1;
+ float rect[4];
+ S32 err = -1;
if(mFullscreen)
{
@@ -1181,10 +785,10 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position)
}
else if(mWindow)
{
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
+ getContentViewBounds(mWindow, rect);
- position->mX = window_rect.left;
- position->mY = window_rect.top;
+ position->mX = rect[0];
+ position->mY = rect[1];
}
else
{
@@ -1196,8 +800,8 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position)
BOOL LLWindowMacOSX::getSize(LLCoordScreen *size)
{
- Rect window_rect;
- OSStatus err = -1;
+ float rect[4];
+ S32 err = -1;
if(mFullscreen)
{
@@ -1207,10 +811,10 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size)
}
else if(mWindow)
{
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
+ getContentViewBounds(mWindow, rect);
- size->mX = window_rect.right - window_rect.left;
- size->mY = window_rect.bottom - window_rect.top;
+ size->mX = rect[2];
+ size->mY = rect[3];
}
else
{
@@ -1222,9 +826,9 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size)
BOOL LLWindowMacOSX::getSize(LLCoordWindow *size)
{
- Rect window_rect;
- OSStatus err = -1;
-
+ float rect[4];
+ S32 err = -1;
+
if(mFullscreen)
{
size->mX = mFullscreenWidth;
@@ -1233,16 +837,16 @@ BOOL LLWindowMacOSX::getSize(LLCoordWindow *size)
}
else if(mWindow)
{
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
-
- size->mX = window_rect.right - window_rect.left;
- size->mY = window_rect.bottom - window_rect.top;
+ getContentViewBounds(mWindow, rect);
+
+ size->mX = rect[2];
+ size->mY = rect[3];
}
else
{
llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl;
}
-
+
return (err == noErr);
}
@@ -1250,7 +854,8 @@ BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position)
{
if(mWindow)
{
- MacMoveWindow(mWindow, position.mX, position.mY, false);
+ float pos[2] = {position.mX, position.mY};
+ setWindowPos(mWindow, pos);
}
return TRUE;
@@ -1260,7 +865,7 @@ BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size)
{
if(mWindow)
{
- SizeWindow(mWindow, size.mX, size.mY, true);
+ setWindowSize(mWindow, size.mX, size.mY);
}
return TRUE;
@@ -1268,15 +873,16 @@ BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size)
BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size)
{
- Rect client_rect;
+ float client_rect[4];
if (mWindow)
{
- OSStatus err = GetWindowBounds(mWindow, kWindowContentRgn, &client_rect);
+ S32 err = noErr;
+ getContentViewBounds(mWindow, client_rect);
if (err == noErr)
{
- client_rect.right = client_rect.left + size.mX;
- client_rect.bottom = client_rect.top + size.mY;
- err = SetWindowBounds(mWindow, kWindowContentRgn, &client_rect);
+ client_rect[2] += size.mX;
+ client_rect[3] += size.mY;
+ setWindowSize(mWindow, client_rect[2], client_rect[3]);
}
if (err == noErr)
{
@@ -1293,12 +899,12 @@ BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size)
void LLWindowMacOSX::swapBuffers()
{
- aglSwapBuffers(mContext);
+ CGLFlushDrawable(mContext);
}
F32 LLWindowMacOSX::getGamma()
{
- F32 result = 1.8; // Default to something sane
+ F32 result = 2.2; // Default to something sane
CGGammaValue redMin;
CGGammaValue redMax;
@@ -1454,39 +1060,15 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
return result;
}
-static void fixOrigin(void)
-{
- GrafPtr port;
- Rect portrect;
-
- ::GetPort(&port);
- ::GetPortBounds(port, &portrect);
- if((portrect.left != 0) || (portrect.top != 0))
- {
- // Mozilla sometimes changes our port origin.
- ::SetOrigin(0,0);
- }
-}
-
BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position)
{
- Point cursor_point;
+ float cursor_point[2];
LLCoordScreen screen_pos;
- GrafPtr save;
if(mWindow == NULL)
return FALSE;
-
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
-
- // gets the mouse location in local coordinates
- ::GetMouse(&cursor_point);
-
-// lldebugs << "getCursorPosition(): cursor is at " << cursor_point.h << ", " << cursor_point.v << " port origin: " << portrect.left << ", " << portrect.top << llendl;
-
- ::SetPort(save);
+
+ getCursorPos(mWindow, cursor_point);
if(mCursorDecoupled)
{
@@ -1499,12 +1081,12 @@ BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position)
// CGGetLastMouseDelta may behave strangely when the cursor's first captured.
// Stash in the event handler instead.
- cursor_point.h += mCursorLastEventDeltaX;
- cursor_point.v += mCursorLastEventDeltaY;
+ cursor_point[0] += mCursorLastEventDeltaX;
+ cursor_point[1] += mCursorLastEventDeltaY;
}
- position->mX = cursor_point.h;
- position->mY = cursor_point.v;
+ position->mX = cursor_point[0];
+ position->mY = cursor_point[1];
return TRUE;
}
@@ -1521,7 +1103,6 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse)
// llinfos << "adjustCursorDecouple: decoupling cursor" << llendl;
CGAssociateMouseAndMouseCursorPosition(false);
mCursorDecoupled = true;
- FlushSpecificEventsFromQueue(GetCurrentEventQueue(), mMoveEventCampartorUPP, NULL);
mCursorIgnoreNextDelta = TRUE;
}
}
@@ -1568,52 +1149,13 @@ F32 LLWindowMacOSX::getPixelAspectRatio()
// MBW -- XXX -- There's got to be a better way than this. Find it, please...
+// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz
void LLWindowMacOSX::beforeDialog()
{
- if(mFullscreen)
- {
-
-#if CAPTURE_ALL_DISPLAYS
- // Uncapture all displays (may want to do this for final build)
- CGReleaseAllDisplays ();
-#else
- // Uncapture only the main display (useful for debugging)
- CGDisplayRelease (mDisplay);
-#endif
- // kDocumentWindowClass
- // kMovableModalWindowClass
- // kAllWindowClasses
-
- // GLint order = 0;
- // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order);
- aglSetDrawable(mContext, NULL);
- // GetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), &oldWindowLevel);
- // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), CGShieldingWindowLevel());
-
- mHandsOffEvents = TRUE;
-
- }
}
void LLWindowMacOSX::afterDialog()
{
- if(mFullscreen)
- {
- mHandsOffEvents = FALSE;
-
- // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), oldWindowLevel);
- aglSetFullScreen(mContext, 0, 0, 0, 0);
- // GLint order = 1;
- // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order);
-
-#if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- CGCaptureAllDisplays ();
-#else
- // Capture only the main display (useful for debugging)
- CGDisplayCapture (mDisplay);
-#endif
- }
}
@@ -1622,14 +1164,10 @@ void LLWindowMacOSX::flashIcon(F32 seconds)
// Don't do this if we're already started, since this would try to install the NMRec twice.
if(!mBounceTimer.getStarted())
{
- OSErr err;
-
+ S32 err = 0;
+ // TODO: Implement icon bouncing
mBounceTime = seconds;
- memset(&mBounceRec, 0, sizeof(mBounceRec));
- mBounceRec.qType = nmType;
- mBounceRec.nmMark = 1;
- err = NMInstall(&mBounceRec);
- if(err == noErr)
+ if(err == 0)
{
mBounceTimer.start();
}
@@ -1643,104 +1181,27 @@ void LLWindowMacOSX::flashIcon(F32 seconds)
BOOL LLWindowMacOSX::isClipboardTextAvailable()
{
- OSStatus err;
- ScrapRef scrap;
- ScrapFlavorFlags flags;
- BOOL result = false;
-
- err = GetCurrentScrap(&scrap);
-
- if(err == noErr)
- {
- err = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &flags);
- }
-
- if(err == noErr)
- result = true;
-
- return result;
+ return pasteBoardAvailable();
}
BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst)
-{
- OSStatus err;
- ScrapRef scrap;
- Size len;
- BOOL result = false;
-
- err = GetCurrentScrap(&scrap);
-
- if(err == noErr)
+{
+ llutf16string str(copyFromPBoard());
+ dst = utf16str_to_wstring(str);
+ if (dst != L"")
{
- err = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &len);
- }
-
- if((err == noErr) && (len > 0))
- {
- int u16len = len / sizeof(U16);
- U16 *temp = new U16[u16len + 1];
- if (temp)
- {
- memset(temp, 0, (u16len + 1) * sizeof(temp[0]));
- err = GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &len, temp);
- if (err == noErr)
- {
- // convert \r\n to \n and \r to \n in the incoming text.
- U16 *s, *d;
- for(s = d = temp; s[0] != '\0'; s++, d++)
- {
- if(s[0] == '\r')
- {
- if(s[1] == '\n')
- {
- // CRLF, a.k.a. DOS newline. Collapse to a single '\n'.
- s++;
- }
-
- d[0] = '\n';
- }
- else
- {
- d[0] = s[0];
- }
- }
-
- d[0] = '\0';
-
- dst = utf16str_to_wstring(temp);
-
- result = true;
- }
- delete[] temp;
- }
+ return true;
+ } else {
+ return false;
}
-
- return result;
}
BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s)
{
- OSStatus err;
- ScrapRef scrap;
- //Size len;
- //char *temp;
BOOL result = false;
-
- if (!s.empty())
- {
- err = GetCurrentScrap(&scrap);
- if (err == noErr)
- err = ClearScrap(&scrap);
-
- if (err == noErr)
- {
- llutf16string utf16str = wstring_to_utf16str(s);
- size_t u16len = utf16str.length() * sizeof(U16);
- err = PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone, u16len, utf16str.data());
- if (err == noErr)
- result = true;
- }
- }
+ llutf16string utf16str = wstring_to_utf16str(s);
+
+ result = copyToPBoard(utf16str.data(), utf16str.length());
return result;
}
@@ -1806,122 +1267,52 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r
BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to)
{
- S32 client_height;
- Rect client_rect;
-
- if(mFullscreen)
- {
- // In the fullscreen case, the "window" is the entire screen.
- client_rect.left = 0;
- client_rect.top = 0;
- client_rect.right = mFullscreenWidth;
- client_rect.bottom = mFullscreenHeight;
- }
- else if (!mWindow ||
- (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) ||
- NULL == to)
- {
- return FALSE;
- }
-
to->mX = from.mX;
- client_height = client_rect.bottom - client_rect.top;
- to->mY = client_height - from.mY - 1;
-
+ to->mY = from.mY;
return TRUE;
}
BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to)
{
- S32 client_height;
- Rect client_rect;
-
- if(mFullscreen)
- {
- // In the fullscreen case, the "window" is the entire screen.
- client_rect.left = 0;
- client_rect.top = 0;
- client_rect.right = mFullscreenWidth;
- client_rect.bottom = mFullscreenHeight;
- }
- else if (!mWindow ||
- (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) ||
- NULL == to)
- {
- return FALSE;
- }
-
to->mX = from.mX;
- client_height = client_rect.bottom - client_rect.top;
- to->mY = client_height - from.mY - 1;
-
+ to->mY = from.mY;
return TRUE;
}
BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to)
{
- if(mFullscreen)
- {
- // In the fullscreen case, window and screen coordinates are the same.
- to->mX = from.mX;
- to->mY = from.mY;
- return TRUE;
- }
- else if(mWindow)
+ if(mWindow)
{
- GrafPtr save;
- Point mouse_point;
-
- mouse_point.h = from.mX;
- mouse_point.v = from.mY;
+ float mouse_point[2];
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
-
- ::GlobalToLocal(&mouse_point);
-
- to->mX = mouse_point.h;
- to->mY = mouse_point.v;
+ mouse_point[0] = from.mX;
+ mouse_point[1] = from.mY;
+
+ convertScreenToWindow(mWindow, mouse_point);
- ::SetPort(save);
+ to->mX = mouse_point[0];
+ to->mY = mouse_point[1];
return TRUE;
}
-
return FALSE;
}
BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to)
{
- if(mFullscreen)
- {
- // In the fullscreen case, window and screen coordinates are the same.
- to->mX = from.mX;
- to->mY = from.mY;
- return TRUE;
- }
- else if(mWindow)
+ if(mWindow)
{
- GrafPtr save;
- Point mouse_point;
-
- mouse_point.h = from.mX;
- mouse_point.v = from.mY;
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
+ float mouse_point[2];
- LocalToGlobal(&mouse_point);
+ mouse_point[0] = from.mX;
+ mouse_point[1] = from.mY;
+ convertWindowToScreen(mWindow, mouse_point);
- to->mX = mouse_point.h;
- to->mY = mouse_point.v;
-
- ::SetPort(save);
+ to->mX = mouse_point[0];
+ to->mY = mouse_point[1];
return TRUE;
}
-
return FALSE;
}
@@ -1949,862 +1340,6 @@ void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& ca
OSMessageBox(text, caption, type);
}
-pascal Boolean LLWindowMacOSX::staticMoveEventComparator( EventRef event, void* data)
-{
- UInt32 evtClass = GetEventClass (event);
- UInt32 evtKind = GetEventKind (event);
-
- if ((evtClass == kEventClassMouse) && ((evtKind == kEventMouseDragged) || (evtKind == kEventMouseMoved)))
- {
- return true;
- }
-
- else
- {
- return false;
- }
-}
-
-
-pascal OSStatus LLWindowMacOSX::staticEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData)
-{
- LLWindowMacOSX *self = (LLWindowMacOSX*)userData;
-
- return(self->eventHandler(myHandler, event));
-}
-
-OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef event)
-{
- OSStatus result = eventNotHandledErr;
- UInt32 evtClass = GetEventClass (event);
- UInt32 evtKind = GetEventKind (event);
-
- // Always handle command events, even in hands-off mode.
- if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
- {
- HICommand command;
- GetEventParameter (event, kEventParamDirectObject, typeHICommand, NULL, sizeof(command), NULL, &command);
-
- switch(command.commandID)
- {
- case kHICommandQuit:
- if(mCallbacks->handleCloseRequest(this))
- {
- // Get the app to initiate cleanup.
- mCallbacks->handleQuit(this);
- // The app is responsible for calling destroyWindow when done with GL
- }
- result = noErr;
- break;
-
- default:
- // MBW -- XXX -- Should we handle other events here?
- break;
- }
- }
-
- if(mHandsOffEvents)
- {
- return(result);
- }
-
- switch (evtClass)
- {
- case kEventClassTextInput:
- {
- switch (evtKind)
- {
- case kEventTextInputUpdateActiveInputArea:
- {
- EventParamType param_type;
-
- long fix_len;
- UInt32 text_len;
- if (mPreeditor
- && (result = GetEventParameter(event, kEventParamTextInputSendFixLen,
- typeLongInteger, &param_type, sizeof(fix_len), NULL, &fix_len)) == noErr
- && typeLongInteger == param_type
- && (result = GetEventParameter(event, kEventParamTextInputSendText,
- typeUnicodeText, &param_type, 0, &text_len, NULL)) == noErr
- && typeUnicodeText == param_type)
- {
- // Handle an optional (but essential to facilitate TSMDA) ReplaceRange param.
- CFRange range;
- if (GetEventParameter(event, kEventParamTextInputSendReplaceRange,
- typeCFRange, &param_type, sizeof(range), NULL, &range) == noErr
- && typeCFRange == param_type)
- {
- // Although the spec. is unclear, replace range should
- // not present when there is an active preedit. We just
- // ignore the case. markAsPreedit will detect the case and warn it.
- const LLWString & text = mPreeditor->getPreeditString();
- const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location);
- const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length);
- mPreeditor->markAsPreedit(location, length);
- }
- mPreeditor->resetPreedit();
-
- // Receive the text from input method.
- U16 *const text = new U16[text_len / sizeof(U16)];
- GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText, NULL, text_len, NULL, text);
- if (fix_len < 0)
- {
- // Do we still need this? Seems obsolete...
- fix_len = text_len;
- }
- const LLWString fix_string
- = utf16str_to_wstring(llutf16string(text, fix_len / sizeof(U16)));
- const LLWString preedit_string
- = utf16str_to_wstring(llutf16string(text + fix_len / sizeof(U16), (text_len - fix_len) / sizeof(U16)));
- delete[] text;
-
- // Handle fixed (comitted) string.
- if (fix_string.length() > 0)
- {
- for (LLWString::const_iterator i = fix_string.begin(); i != fix_string.end(); i++)
- {
- mPreeditor->handleUnicodeCharHere(*i);
- }
- }
-
- // Receive the segment info and caret position.
- LLPreeditor::segment_lengths_t preedit_segment_lengths;
- LLPreeditor::standouts_t preedit_standouts;
- S32 caret_position = preedit_string.length();
- UInt32 text_range_array_size;
- if (GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
- &param_type, 0, &text_range_array_size, NULL) == noErr
- && typeTextRangeArray == param_type
- && text_range_array_size > sizeof(TextRangeArray))
- {
- // TextRangeArray is a variable-length struct.
- TextRangeArray * const text_range_array = (TextRangeArray *) new char[text_range_array_size];
- GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray,
- NULL, text_range_array_size, NULL, text_range_array);
-
- // WARNING: We assume ranges are in ascending order,
- // although the condition is undocumented. It seems
- // OK to assume this. I also assumed
- // the ranges are contiguous in previous versions, but I
- // have heard a rumore that older versions os ATOK may
- // return ranges with some _gap_. I don't know whether
- // it is true, but I'm preparing my code for the case.
-
- const S32 ranges = text_range_array->fNumOfRanges;
- preedit_segment_lengths.reserve(ranges);
- preedit_standouts.reserve(ranges);
-
- S32 last_bytes = 0;
- S32 last_utf32 = 0;
- for (S32 i = 0; i < ranges; i++)
- {
- const TextRange &range = text_range_array->fRange[i];
- if (range.fStart > last_bytes)
- {
- const S32 length_utf16 = (range.fStart - last_bytes) / sizeof(U16);
- const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
- preedit_segment_lengths.push_back(length_utf32);
- preedit_standouts.push_back(FALSE);
- last_utf32 += length_utf32;
- }
- if (range.fEnd > range.fStart)
- {
- const S32 length_utf16 = (range.fEnd - range.fStart) / sizeof(U16);
- const S32 length_utf32 = wstring_wstring_length_from_utf16_length(preedit_string, last_utf32, length_utf16);
- preedit_segment_lengths.push_back(length_utf32);
- preedit_standouts.push_back(
- kTSMHiliteSelectedRawText == range.fHiliteStyle
- || kTSMHiliteSelectedConvertedText == range.fHiliteStyle
- || kTSMHiliteSelectedText == range.fHiliteStyle);
- last_utf32 += length_utf32;
- }
- if (kTSMHiliteCaretPosition == range.fHiliteStyle)
- {
- caret_position = last_utf32;
- }
- last_bytes = range.fEnd;
- }
- if (preedit_string.length() > last_utf32)
- {
- preedit_segment_lengths.push_back(preedit_string.length() - last_utf32);
- preedit_standouts.push_back(FALSE);
- }
-
- delete[] (char *) text_range_array;
- }
-
- // Handle preedit string.
- if (preedit_string.length() == 0)
- {
- preedit_segment_lengths.clear();
- preedit_standouts.clear();
- }
- else if (preedit_segment_lengths.size() == 0)
- {
- preedit_segment_lengths.push_back(preedit_string.length());
- preedit_standouts.push_back(FALSE);
- }
- mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position);
-
- result = noErr;
- }
- }
- break;
-
- case kEventTextInputUnicodeForKeyEvent:
- {
- UInt32 modifiers = 0;
-
-
- // First, process the raw event.
- {
- EventRef rawEvent = NULL;
-
- // Get the original event and extract the modifier keys, so we can ignore command-key events.
- if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr)
- {
- // Grab the modifiers for later use in this function...
- GetEventParameter (rawEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
-
- // and call this function recursively to handle the raw key event.
- eventHandler (myHandler, rawEvent);
-
- // save the raw event until we're done processing the unicode input as well.
- mRawKeyEvent = rawEvent;
- }
- }
-
- OSStatus err = noErr;
- EventParamType actualType = typeUnicodeText;
- UInt32 actualSize = 0;
- size_t actualCount = 0;
- U16 *buffer = NULL;
-
- // Get the size of the unicode data
- err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, 0, &actualSize, NULL);
- if(err == noErr)
- {
- // allocate a buffer and get the actual data.
- actualCount = actualSize / sizeof(U16);
- buffer = new U16[actualCount];
- err = GetEventParameter (event, kEventParamTextInputSendText, typeUnicodeText, &actualType, actualSize, &actualSize, buffer);
- }
-
- if(err == noErr)
- {
- if(modifiers & (cmdKey | controlKey))
- {
- // This was a menu key equivalent. Ignore it.
- }
- else
- {
- MASK mask = LLWindowMacOSX::modifiersToMask(modifiers);
-
- llassert( actualType == typeUnicodeText );
-
- // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar.
-
- // Convert to UTF32 and go character-by-character.
- llutf16string utf16(buffer, actualCount);
- LLWString utf32 = utf16str_to_wstring(utf16);
- LLWString::iterator iter;
-
- for(iter = utf32.begin(); iter != utf32.end(); iter++)
- {
- mCallbacks->handleUnicodeChar(*iter, mask);
- }
- }
- }
-
- if(buffer != NULL)
- {
- delete[] buffer;
- }
-
- mRawKeyEvent = NULL;
- result = err;
- }
- break;
-
- case kEventTextInputOffsetToPos:
- {
- EventParamType param_type;
- long offset;
- if (mPreeditor
- && GetEventParameter(event, kEventParamTextInputSendTextOffset, typeLongInteger,
- &param_type, sizeof(offset), NULL, &offset) == noErr
- && typeLongInteger == param_type)
- {
- S32 preedit, preedit_length;
- mPreeditor->getPreeditRange(&preedit, &preedit_length);
- const LLWString & text = mPreeditor->getPreeditString();
-
- LLCoordGL caret_coord;
- LLRect preedit_bounds;
- if (0 <= offset
- && mPreeditor->getPreeditLocation(wstring_wstring_length_from_utf16_length(text, preedit, offset / sizeof(U16)),
- &caret_coord, &preedit_bounds, NULL))
- {
- LLCoordGL caret_base_coord(caret_coord.mX, preedit_bounds.mBottom);
- LLCoordScreen caret_base_coord_screen;
- convertCoords(caret_base_coord, &caret_base_coord_screen);
- Point qd_point;
- qd_point.h = caret_base_coord_screen.mX;
- qd_point.v = caret_base_coord_screen.mY;
- SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint, sizeof(qd_point), &qd_point);
-
- short line_height = (short) preedit_bounds.getHeight();
- SetEventParameter(event, kEventParamTextInputReplyLineHeight, typeShortInteger, sizeof(line_height), &line_height);
-
- result = noErr;
- }
- else
- {
- result = errOffsetInvalid;
- }
- }
- }
- break;
-
- case kEventTextInputGetSelectedText:
- {
- if (mPreeditor)
- {
- S32 selection, selection_length;
- mPreeditor->getSelectionRange(&selection, &selection_length);
- if (selection_length)
- {
- const LLWString text = mPreeditor->getPreeditString().substr(selection, selection_length);
- const llutf16string text_utf16 = wstring_to_utf16str(text);
- result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText,
- text_utf16.length() * sizeof(U16), text_utf16.c_str());
- }
- }
- }
- break;
- }
- }
- break;
-
- case kEventClassKeyboard:
- {
- UInt32 keyCode = 0;
- char charCode = 0;
- UInt32 modifiers = 0;
-
- // Some of these may fail for some event types. That's fine.
- GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode);
- GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers);
-
- // save the raw event so getNativeKeyData can use it.
- mRawKeyEvent = event;
-
- // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers);
- // fflush(stdout);
-
- switch (evtKind)
- {
- case kEventRawKeyDown:
- case kEventRawKeyRepeat:
- if (gDebugWindowProc)
- {
- printf("key down, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n",
- (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers);
- fflush(stdout);
- }
- gKeyboard->handleKeyDown(keyCode, modifiers);
- result = eventNotHandledErr;
- break;
-
- case kEventRawKeyUp:
- if (gDebugWindowProc)
- {
- printf("key up, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n",
- (unsigned int)keyCode, charCode, (char)charCode, (unsigned int)modifiers);
- fflush(stdout);
- }
- gKeyboard->handleKeyUp(keyCode, modifiers);
- result = eventNotHandledErr;
- break;
-
- case kEventRawKeyModifiersChanged:
- // The keyboard input system wants key up/down events for modifier keys.
- // Mac OS doesn't supply these directly, but can supply events when the collective modifier state changes.
- // Use these events to generate up/down events for the modifiers.
-
- if((modifiers & shiftKey) && !(mLastModifiers & shiftKey))
- {
- if (gDebugWindowProc) printf("Shift key down event\n");
- gKeyboard->handleKeyDown(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000));
- }
- else if(!(modifiers & shiftKey) && (mLastModifiers & shiftKey))
- {
- if (gDebugWindowProc) printf("Shift key up event\n");
- gKeyboard->handleKeyUp(0x38, (modifiers & 0x00FFFFFF) | ((0x38 << 24) & 0xFF000000));
- }
-
- if((modifiers & alphaLock) && !(mLastModifiers & alphaLock))
- {
- if (gDebugWindowProc) printf("Caps lock down event\n");
- gKeyboard->handleKeyDown(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000));
- }
- else if(!(modifiers & alphaLock) && (mLastModifiers & alphaLock))
- {
- if (gDebugWindowProc) printf("Caps lock up event\n");
- gKeyboard->handleKeyUp(0x39, (modifiers & 0x00FFFFFF) | ((0x39 << 24) & 0xFF000000));
- }
-
- if((modifiers & controlKey) && !(mLastModifiers & controlKey))
- {
- if (gDebugWindowProc) printf("Control key down event\n");
- gKeyboard->handleKeyDown(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000));
- }
- else if(!(modifiers & controlKey) && (mLastModifiers & controlKey))
- {
- if (gDebugWindowProc) printf("Control key up event\n");
- gKeyboard->handleKeyUp(0x3b, (modifiers & 0x00FFFFFF) | ((0x3b << 24) & 0xFF000000));
- }
-
- if((modifiers & optionKey) && !(mLastModifiers & optionKey))
- {
- if (gDebugWindowProc) printf("Option key down event\n");
- gKeyboard->handleKeyDown(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000));
- }
- else if(!(modifiers & optionKey) && (mLastModifiers & optionKey))
- {
- if (gDebugWindowProc) printf("Option key up event\n");
- gKeyboard->handleKeyUp(0x3a, (modifiers & 0x00FFFFFF) | ((0x3a << 24) & 0xFF000000));
- }
-
- // When the state of the 'Fn' key (the one that changes some of the mappings on a powerbook/macbook keyboard
- // to an embedded keypad) changes, it may subsequently cause a key up event to be lost, which may lead to
- // a movement key getting "stuck" down. This is bad.
- // This is an OS bug -- even the GetKeys() API doesn't tell you the key has been released.
- // This workaround causes all held-down keys to be reset whenever the state of the Fn key changes. This isn't
- // exactly what we want, but it does avoid the case where you get stuck running forward.
- if((modifiers & kEventKeyModifierFnMask) != (mLastModifiers & kEventKeyModifierFnMask))
- {
- if (gDebugWindowProc) printf("Fn key state change event\n");
- gKeyboard->resetKeys();
- }
-
- if (gDebugWindowProc) fflush(stdout);
-
- mLastModifiers = modifiers;
- result = eventNotHandledErr;
- break;
- }
-
- mRawKeyEvent = NULL;
- }
- break;
-
- case kEventClassMouse:
- {
- result = CallNextEventHandler(myHandler, event);
- if (eventNotHandledErr == result)
- { // only handle events not already handled (prevents wierd resize interaction)
- EventMouseButton button = kEventMouseButtonPrimary;
- HIPoint location = {0.0f, 0.0f};
- UInt32 modifiers = 0;
- UInt32 clickCount = 1;
- long wheelDelta = 0;
- LLCoordScreen inCoords;
- LLCoordGL outCoords;
- MASK mask = 0;
-
- GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button);
- GetEventParameter(event, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(location), NULL, &location);
- GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(modifiers), NULL, &modifiers);
- GetEventParameter(event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(wheelDelta), NULL, &wheelDelta);
- GetEventParameter(event, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
-
- inCoords.mX = llround(location.x);
- inCoords.mY = llround(location.y);
-
- if(modifiers & shiftKey) { mask |= MASK_SHIFT; }
- if(modifiers & controlKey) { mask |= MASK_CONTROL; }
- if(modifiers & optionKey) { mask |= MASK_ALT; }
-
- if(mCursorDecoupled)
- {
- CGMouseDelta x, y;
-
- // If the cursor's decoupled, we need to read the latest movement delta as well.
- CGGetLastMouseDelta( &x, &y );
- mCursorLastEventDeltaX = x;
- mCursorLastEventDeltaY = y;
-
- if(mCursorIgnoreNextDelta)
- {
- mCursorLastEventDeltaX = 0;
- mCursorLastEventDeltaY = 0;
- mCursorIgnoreNextDelta = FALSE;
- }
- }
- else
- {
- mCursorLastEventDeltaX = 0;
- mCursorLastEventDeltaY = 0;
- }
-
- inCoords.mX += mCursorLastEventDeltaX;
- inCoords.mY += mCursorLastEventDeltaY;
-
- convertCoords(inCoords, &outCoords);
-
- // printf("coords in: %d, %d; coords out: %d, %d\n", inCoords.mX, inCoords.mY, outCoords.mX, outCoords.mY);
- // fflush(stdout);
-
-
- switch (evtKind)
- {
- case kEventMouseDown:
- if (mLanguageTextInputAllowed)
- {
- // We need to interrupt before handling mouse events,
- // so that the fixed string from IM are delivered to
- // the currently focused UI component.
- interruptLanguageTextInput();
- }
- switch(button)
- {
- case kEventMouseButtonPrimary:
- if(modifiers & cmdKey)
- {
- // Simulate a right click
- mSimulatedRightClick = true;
- mCallbacks->handleRightMouseDown(this, outCoords, mask);
- }
- else if(clickCount == 2)
- {
- // Windows double-click events replace the second mousedown event in a double-click.
- mCallbacks->handleDoubleClick(this, outCoords, mask);
- }
- else
- {
- mCallbacks->handleMouseDown(this, outCoords, mask);
- }
- break;
- case kEventMouseButtonSecondary:
- mCallbacks->handleRightMouseDown(this, outCoords, mask);
- break;
-
- case kEventMouseButtonTertiary:
- mCallbacks->handleMiddleMouseDown(this, outCoords, mask);
- break;
- }
- result = noErr;
- break;
- case kEventMouseUp:
-
- switch(button)
- {
- case kEventMouseButtonPrimary:
- if(mSimulatedRightClick)
- {
- // End of simulated right click
- mSimulatedRightClick = false;
- mCallbacks->handleRightMouseUp(this, outCoords, mask);
- }
- else
- {
- mCallbacks->handleMouseUp(this, outCoords, mask);
- }
- break;
- case kEventMouseButtonSecondary:
- mCallbacks->handleRightMouseUp(this, outCoords, mask);
- break;
-
- case kEventMouseButtonTertiary:
- mCallbacks->handleMiddleMouseUp(this, outCoords, mask);
- break;
- }
- result = noErr;
- break;
-
- case kEventMouseWheelMoved:
- {
- static S32 z_delta = 0;
-
- z_delta += wheelDelta;
-
- if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta)
- {
- mCallbacks->handleScrollWheel(this, -z_delta / WHEEL_DELTA);
- z_delta = 0;
- }
- }
- result = noErr;
- break;
-
- case kEventMouseDragged:
- case kEventMouseMoved:
- mCallbacks->handleMouseMove(this, outCoords, mask);
- result = noErr;
- break;
-
- }
- }
- }
- break;
-
- case kEventClassWindow:
- switch(evtKind)
- {
- case kEventWindowActivated:
- if (mTSMDocument)
- {
- ActivateTSMDocument(mTSMDocument);
- }
- mCallbacks->handleFocus(this);
- break;
- case kEventWindowDeactivated:
- if (mTSMDocument)
- {
- DeactivateTSMDocument(mTSMDocument);
- }
- mCallbacks->handleFocusLost(this);
- break;
-
- case kEventWindowBoundsChanging:
- {
- // This is where we would constrain move/resize to a particular screen
-
- const S32 MIN_WIDTH = mMinWindowWidth;
- const S32 MIN_HEIGHT = mMinWindowHeight;
-
- Rect currentBounds;
- Rect previousBounds;
-
- GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &currentBounds);
- GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &previousBounds);
-
- // Put an offset into window un-maximize operation since the kEventWindowGetIdealSize
- // event only allows the specification of size and not position.
- if (mMaximized)
- {
- short leftOffset = mPreviousWindowRect.left - currentBounds.left;
- currentBounds.left += leftOffset;
- currentBounds.right += leftOffset;
-
- short topOffset = mPreviousWindowRect.top - currentBounds.top;
- currentBounds.top += topOffset;
- currentBounds.bottom += topOffset;
- }
- else
- {
- // Store off the size for future un-maximize operations
- mPreviousWindowRect = previousBounds;
- }
-
- if ((currentBounds.right - currentBounds.left) < MIN_WIDTH)
- {
- currentBounds.right = currentBounds.left + MIN_WIDTH;
- }
-
- if ((currentBounds.bottom - currentBounds.top) < MIN_HEIGHT)
- {
- currentBounds.bottom = currentBounds.top + MIN_HEIGHT;
- }
-
- SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), &currentBounds);
- result = noErr;
- }
- break;
-
- case kEventWindowBoundsChanged:
- {
- // Get new window bounds
- Rect newBounds;
- GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &newBounds);
-
- // Get previous window bounds
- Rect oldBounds;
- GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &oldBounds);
-
- // Determine if the new size is larger than the old
- bool newBoundsLarger = ((newBounds.right - newBounds.left) >= (oldBounds.right - oldBounds.left));
- newBoundsLarger &= ((newBounds.bottom - newBounds.top) >= (oldBounds.bottom - oldBounds.top));
-
- // Check to see if this is a zoom event (+ button on window pane)
- unsigned int eventParams;
- GetEventParameter(event, kEventParamAttributes, typeUInt32, NULL, sizeof(int), NULL, &eventParams);
- bool isZoomEvent = ((eventParams & kWindowBoundsChangeZoom) != 0);
-
- // Maximized flag is if zoom event and increasing window size
- mMaximized = (isZoomEvent && newBoundsLarger);
-
- aglUpdateContext(mContext);
-
- mCallbacks->handleResize(this, newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
- }
- break;
-
- case kEventWindowGetIdealSize:
- // Only recommend a new ideal size when un-maximizing
- if (mMaximized == TRUE)
- {
- Point nonMaximizedSize;
-
- nonMaximizedSize.v = mPreviousWindowRect.bottom - mPreviousWindowRect.top;
- nonMaximizedSize.h = mPreviousWindowRect.right - mPreviousWindowRect.left;
-
- SetEventParameter(event, kEventParamDimensions, typeQDPoint, sizeof(Point), &nonMaximizedSize);
- result = noErr;
- }
- break;
-
- case kEventWindowClose:
- if(mCallbacks->handleCloseRequest(this))
- {
- // Get the app to initiate cleanup.
- mCallbacks->handleQuit(this);
- // The app is responsible for calling destroyWindow when done with GL
- }
- result = noErr;
- break;
-
- case kEventWindowHidden:
- // llinfos << "LLWindowMacOSX: Deactivating on hide" << llendl;
- mMinimized = TRUE;
- mCallbacks->handleActivate(this, false);
- // result = noErr;
- break;
-
- case kEventWindowShown:
- // llinfos << "LLWindowMacOSX: Activating on show" << llendl;
- mMinimized = FALSE;
- mCallbacks->handleActivate(this, true);
- // result = noErr;
- break;
-
- case kEventWindowCollapsed:
- // llinfos << "LLWindowMacOSX: Deactivating on collapse" << llendl;
- mMinimized = TRUE;
- mCallbacks->handleActivate(this, false);
- // result = noErr;
- break;
-
- case kEventWindowExpanded:
- // llinfos << "LLWindowMacOSX: Activating on expand" << llendl;
- mMinimized = FALSE;
- mCallbacks->handleActivate(this, true);
- // result = noErr;
- break;
-
- case kEventWindowGetClickActivation:
- // BringToFront(mWindow);
- // result = noErr;
- break;
- }
- break;
-
- case kEventClassTSMDocumentAccess:
- if (mPreeditor)
- {
- switch(evtKind)
- {
-
- case kEventTSMDocumentAccessGetLength:
- {
- // Return the number of UTF-16 units in the text, excluding those for preedit.
-
- S32 preedit, preedit_length;
- mPreeditor->getPreeditRange(&preedit, &preedit_length);
- const LLWString & text = mPreeditor->getPreeditString();
- const CFIndex length = wstring_utf16_length(text, 0, preedit)
- + wstring_utf16_length(text, preedit + preedit_length, text.length());
- result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length);
- }
- break;
-
- case kEventTSMDocumentAccessGetSelectedRange:
- {
- // Return the selected range, excluding preedit.
- // In our preeditor, preedit and selection are exclusive, so,
- // when it has a preedit, there is no selection and the
- // insertion point is on the preedit that corrupses into the
- // beginning of the preedit when the preedit was removed.
-
- S32 preedit, preedit_length;
- mPreeditor->getPreeditRange(&preedit, &preedit_length);
- const LLWString & text = mPreeditor->getPreeditString();
-
- CFRange range;
- if (preedit_length)
- {
- range.location = wstring_utf16_length(text, 0, preedit);
- range.length = 0;
- }
- else
- {
- S32 selection, selection_length;
- mPreeditor->getSelectionRange(&selection, &selection_length);
- range.location = wstring_utf16_length(text, 0, selection);
- range.length = wstring_utf16_length(text, selection, selection_length);
- }
-
- result = SetEventParameter(event, kEventParamTSMDocAccessReplyCharacterRange, typeCFRange, sizeof(range), &range);
- }
- break;
-
- case kEventTSMDocumentAccessGetCharacters:
- {
- UniChar *target_pointer;
- CFRange range;
- EventParamType param_type;
- if ((result = GetEventParameter(event, kEventParamTSMDocAccessSendCharacterRange,
- typeCFRange, &param_type, sizeof(range), NULL, &range)) == noErr
- && typeCFRange == param_type
- && (result = GetEventParameter(event, kEventParamTSMDocAccessSendCharactersPtr,
- typePtr, &param_type, sizeof(target_pointer), NULL, &target_pointer)) == noErr
- && typePtr == param_type)
- {
- S32 preedit, preedit_length;
- mPreeditor->getPreeditRange(&preedit, &preedit_length);
- const LLWString & text = mPreeditor->getPreeditString();
-
- // The GetCharacters event of TSMDA has a fundamental flaw;
- // An input method need to decide the starting offset and length
- // *before* it actually see the contents, so it is impossible
- // to guarantee the character-aligned access. The event reply
- // has no way to indicate a condition something like "Request
- // was not fulfilled due to unaligned access. Please retry."
- // Any error sent back to the input method stops use of TSMDA
- // entirely during the session...
- // We need to simulate very strictly the behaviour as if the
- // underlying *text engine* holds the contents in UTF-16.
- // I guess this is the reason why Apple repeats saying "all
- // text handling application should use UTF-16." They are
- // trying to _fix_ the flaw by changing the appliations...
- // ... or, domination of UTF-16 in the industry may be a part
- // of the company vision, and Apple is trying to force third
- // party developers to obey their vision. Remember that use
- // of 16 bits per _a_character_ was one of the very fundamental
- // Unicode design policy on its early days (during late 80s)
- // and the original Unicode design was by two Apple employees...
-
- const llutf16string text_utf16
- = wstring_to_utf16str(text, preedit)
- + wstring_to_utf16str(text.substr(preedit + preedit_length));
-
- llassert_always(sizeof(U16) == sizeof(UniChar));
- llassert(0 <= range.location && 0 <= range.length && range.location + range.length <= text_utf16.length());
- memcpy(target_pointer, text_utf16.c_str() + range.location, range.length * sizeof(UniChar));
-
- // Note that result has already been set above.
- }
- }
- break;
-
- }
- }
- break;
- }
- return result;
-}
-
const char* cursorIDToName(int id)
{
switch (id)
@@ -2876,7 +1411,7 @@ static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY)
void LLWindowMacOSX::updateCursor()
{
- OSStatus result = noErr;
+ S32 result = 0;
if (mDragOverrideCursor != -1)
{
@@ -2909,11 +1444,11 @@ void LLWindowMacOSX::updateCursor()
{
default:
case UI_CURSOR_ARROW:
- InitCursor();
+ setArrowCursor();
if(mCursorHidden)
{
// Since InitCursor resets the hide level, correct for it here.
- ::HideCursor();
+ hideNSCursor();
}
break;
@@ -2921,12 +1456,12 @@ void LLWindowMacOSX::updateCursor()
// Find out what they look like and replicate them.
// These are essentially correct
- case UI_CURSOR_WAIT: SetThemeCursor(kThemeWatchCursor); break;
- case UI_CURSOR_IBEAM: SetThemeCursor(kThemeIBeamCursor); break;
- case UI_CURSOR_CROSS: SetThemeCursor(kThemeCrossCursor); break;
- case UI_CURSOR_HAND: SetThemeCursor(kThemePointingHandCursor); break;
+ case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break;
+ case UI_CURSOR_IBEAM: setIBeamCursor(); break;
+ case UI_CURSOR_CROSS: setCrossCursor(); break;
+ case UI_CURSOR_HAND: setPointingHandCursor(); break;
// case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break;
- case UI_CURSOR_ARROWCOPY: SetThemeCursor(kThemeCopyArrowCursor); break;
+ case UI_CURSOR_ARROWCOPY: setCopyCursor(); break;
// Double-check these
case UI_CURSOR_NO:
@@ -2969,7 +1504,7 @@ void LLWindowMacOSX::updateCursor()
if(result != noErr)
{
- InitCursor();
+ setArrowCursor();
}
mCurrentCursor = mNextCursor;
@@ -3039,7 +1574,7 @@ void LLWindowMacOSX::hideCursor()
// llinfos << "hideCursor: hiding" << llendl;
mCursorHidden = TRUE;
mHideCursorPermanent = TRUE;
- ::HideCursor();
+ hideNSCursor();
}
else
{
@@ -3056,7 +1591,7 @@ void LLWindowMacOSX::showCursor()
// llinfos << "showCursor: showing" << llendl;
mCursorHidden = FALSE;
mHideCursorPermanent = FALSE;
- ::ShowCursor();
+ showNSCursor();
}
else
{
@@ -3102,7 +1637,7 @@ void LLSplashScreenMacOSX::showImpl()
// This code _could_ be used to display a spash screen...
#if 0
IBNibRef nib = NULL;
- OSStatus err;
+ S32 err;
err = CreateNibReference(CFSTR("SecondLife"), &nib);
@@ -3127,25 +1662,6 @@ void LLSplashScreenMacOSX::updateImpl(const std::string& mesg)
CFStringRef string = NULL;
string = CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8);
-
- if(string != NULL)
- {
- ControlRef progressText = NULL;
- ControlID id;
- OSStatus err;
-
- id.signature = 'what';
- id.id = 0;
-
- err = GetControlByID(mWindow, &id, &progressText);
- if(err == noErr)
- {
- err = SetControlData(progressText, kControlEntireControl, kControlStaticTextCFStringTag, sizeof(CFStringRef), (Ptr)&string);
- Draw1Control(progressText);
- }
-
- CFRelease(string);
- }
}
}
@@ -3154,7 +1670,6 @@ void LLSplashScreenMacOSX::hideImpl()
{
if(mWindow != NULL)
{
- DisposeWindow(mWindow);
mWindow = NULL;
}
}
@@ -3163,102 +1678,16 @@ void LLSplashScreenMacOSX::hideImpl()
S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type)
{
- S32 result = OSBTN_CANCEL;
- SInt16 retval_mac = 1;
- AlertStdCFStringAlertParamRec params;
- CFStringRef errorString = NULL;
- CFStringRef explanationString = NULL;
- DialogRef alert = NULL;
- AlertType alertType = kAlertCautionAlert;
- OSStatus err;
-
- explanationString = CFStringCreateWithCString(NULL, text.c_str(), kCFStringEncodingUTF8);
- errorString = CFStringCreateWithCString(NULL, caption.c_str(), kCFStringEncodingUTF8);
-
- params.version = kStdCFStringAlertVersionOne;
- params.movable = false;
- params.helpButton = false;
- params.defaultText = (CFStringRef)kAlertDefaultOKText;
- params.cancelText = 0;
- params.otherText = 0;
- params.defaultButton = 1;
- params.cancelButton = 0;
- params.position = kWindowDefaultPosition;
- params.flags = 0;
-
- switch(type)
- {
- case OSMB_OK:
- default:
- break;
- case OSMB_OKCANCEL:
- params.cancelText = (CFStringRef)kAlertDefaultCancelText;
- params.cancelButton = 2;
- break;
- case OSMB_YESNO:
- alertType = kAlertNoteAlert;
- params.defaultText = CFSTR("Yes");
- params.cancelText = CFSTR("No");
- params.cancelButton = 2;
- break;
- }
-
- if(gWindowImplementation != NULL)
- gWindowImplementation->beforeDialog();
-
- err = CreateStandardAlert(
- alertType,
- errorString,
- explanationString,
- &params,
- &alert);
-
- if(err == noErr)
- {
- err = RunStandardAlert(
- alert,
- NULL,
- &retval_mac);
- }
-
- if(gWindowImplementation != NULL)
- gWindowImplementation->afterDialog();
-
- switch(type)
- {
- case OSMB_OK:
- case OSMB_OKCANCEL:
- default:
- if(retval_mac == 1)
- result = OSBTN_OK;
- else
- result = OSBTN_CANCEL;
- break;
- case OSMB_YESNO:
- if(retval_mac == 1)
- result = OSBTN_YES;
- else
- result = OSBTN_NO;
- break;
- }
-
- if(errorString != NULL)
- {
- CFRelease(errorString);
- }
-
- if(explanationString != NULL)
- {
- CFRelease(explanationString);
- }
-
- return result;
+ // TODO: Implement a native NSAlert function that replicates all of this.
+ return 0;
}
// Open a URL with the user's default web browser.
// Must begin with protocol identifier.
void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
{
+ // I'm fairly certain that this is all legitimate under Apple's currently supported APIs.
+
bool found = false;
S32 i;
for (i = 0; i < gURLProtocolWhitelistCount; i++)
@@ -3276,7 +1705,7 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
return;
}
- OSStatus result = noErr;
+ S32 result = 0;
CFURLRef urlRef = NULL;
llinfos << "Opening URL " << escaped_url << llendl;
@@ -3313,7 +1742,7 @@ void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async)
LLSD LLWindowMacOSX::getNativeKeyData()
{
LLSD result = LLSD::emptyMap();
-
+#if 0
if(mRawKeyEvent)
{
char char_code = 0;
@@ -3335,7 +1764,7 @@ LLSD LLWindowMacOSX::getNativeKeyData()
// This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc)
// cause llsd serialization to create XML that the llsd deserializer won't parse!
std::string unicode;
- OSStatus err = noErr;
+ S32 err = noErr;
EventParamType actualType = typeUTF8Text;
UInt32 actualSize = 0;
char *buffer = NULL;
@@ -3357,7 +1786,7 @@ LLSD LLWindowMacOSX::getNativeKeyData()
#endif
}
-
+#endif
lldebugs << "native key data is: " << result << llendl;
@@ -3367,34 +1796,9 @@ LLSD LLWindowMacOSX::getNativeKeyData()
BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b)
{
+ // Is this even used anywhere? Do we really need an OS color picker?
BOOL retval = FALSE;
- OSErr error = noErr;
- NColorPickerInfo info;
-
- memset(&info, 0, sizeof(info));
- info.theColor.color.rgb.red = (UInt16)(*r * 65535.f);
- info.theColor.color.rgb.green = (UInt16)(*g * 65535.f);
- info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f);
- info.placeWhere = kCenterOnMainScreen;
-
- if(gWindowImplementation != NULL)
- gWindowImplementation->beforeDialog();
-
- error = NPickColor(&info);
-
- if(gWindowImplementation != NULL)
- gWindowImplementation->afterDialog();
-
- if (error == noErr)
- {
- retval = info.newColorChosen;
- if (info.newColorChosen)
- {
- *r = ((float) info.theColor.color.rgb.red) / 65535.0;
- *g = ((float) info.theColor.color.rgb.green) / 65535.0;
- *b = ((float) info.theColor.color.rgb.blue) / 65535.0;
- }
- }
+ //S32 error = 0;
return (retval);
}
@@ -3405,44 +1809,13 @@ void *LLWindowMacOSX::getPlatformWindow()
return (void*)mWindow;
}
-void *LLWindowMacOSX::getMediaWindow()
-{
- /*
- Mozilla needs to be initialized with a WindowRef to function properly.
- (There's no good reason for this, since it shouldn't be interacting with our window in any way, but that's another issue.)
- If we're in windowed mode, we _could_ hand it our actual window pointer, but a subsequent switch to fullscreen will destroy that window,
- which trips up Mozilla.
- Instead of using our actual window, we create an invisible window which will persist for the lifetime of the application and pass that to Mozilla.
- This satisfies its deep-seated need to latch onto a WindowRef and solves the issue with switching between fullscreen and windowed modes.
-
- Note that we will never destroy this window (by design!), but since only one will ever be created per run of the application, that's okay.
- */
-
- if(sMediaWindow == NULL)
- {
- Rect window_rect = {100, 100, 200, 200};
-
- sMediaWindow = NewCWindow(
- NULL,
- &window_rect,
- (ConstStr255Param) "\p",
- false, // Create the window invisible.
- zoomDocProc, // Window with a grow box and a zoom box
- kLastWindowOfClass, // create it behind other windows
- false, // no close box
- 0);
- }
-
- return (void*)sMediaWindow;
-}
-
void LLWindowMacOSX::stopDockTileBounce()
{
- NMRemove(&mBounceRec);
mBounceTimer.stop();
}
// get a double value from a dictionary
+/*
static double getDictDouble (CFDictionaryRef refDict, CFStringRef key)
{
double double_value;
@@ -3452,7 +1825,7 @@ static double getDictDouble (CFDictionaryRef refDict, CFStringRef key)
if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it
return -1; // fail
return double_value; // otherwise return the long value
-}
+}*/
// get a long value from a dictionary
static long getDictLong (CFDictionaryRef refDict, CFStringRef key)
@@ -3468,8 +1841,8 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key)
void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
{
- ScriptLanguageRecord script_language;
-
+ allowDirectMarkedTextInput(b, mGLView);
+
if (preeditor != mPreeditor && !b)
{
// This condition may occur by a call to
@@ -3480,9 +1853,7 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
// is not disturbed.
return;
}
-
- UseInputWindow(mTSMDocument, !b);
-
+
// Take care of old and new preeditors.
if (preeditor != mPreeditor || !b)
{
@@ -3495,44 +1866,17 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b)
}
mPreeditor = (b ? preeditor : NULL);
}
-
+
if (b == mLanguageTextInputAllowed)
{
return;
}
mLanguageTextInputAllowed = b;
-
- if (b)
- {
- if (mTSMScriptCode != smRoman)
- {
- script_language.fScript = mTSMScriptCode;
- script_language.fLanguage = mTSMLangCode;
- SetTextServiceLanguage(&script_language);
- }
- }
- else
- {
- GetTextServiceLanguage(&script_language);
- mTSMScriptCode = script_language.fScript;
- mTSMLangCode = script_language.fLanguage;
- if (mTSMScriptCode != smRoman)
- {
- script_language.fScript = smRoman;
- script_language.fLanguage = langEnglish;
- SetTextServiceLanguage(&script_language);
- }
- }
}
void LLWindowMacOSX::interruptLanguageTextInput()
{
- if (mTSMDocument)
- {
- FixTSMDocument(mTSMDocument);
- }
- // Don't we need to call resetPreedit here?
- // Well, if Apple's TSM document is correct, we don't.
+ commitCurrentPreedit(mGLView);
}
//static
@@ -3543,21 +1887,21 @@ std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList()
}
// static
-MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers)
+MASK LLWindowMacOSX::modifiersToMask(S16 modifiers)
{
MASK mask = 0;
- if(modifiers & shiftKey) { mask |= MASK_SHIFT; }
- if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; }
- if(modifiers & optionKey) { mask |= MASK_ALT; }
+ if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; }
+ if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; }
+ if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; }
return mask;
}
#if LL_OS_DRAGDROP_ENABLED
-
-OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow,
+/*
+S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow,
void * handlerRefCon, DragRef drag)
{
- OSErr result = noErr;
+ S16 result = 0;
LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon;
lldebugs << "drag tracking handler, message = " << message << llendl;
@@ -3582,7 +1926,6 @@ OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef
return result;
}
-
OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon,
DragRef drag)
{
@@ -3590,126 +1933,69 @@ OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefC
return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED);
}
-
-OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDropAction action)
+*/
+void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action)
{
- OSErr result = dragNotAcceptedErr; // overall function result
- OSErr err = noErr; // for local error handling
+ MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers());
- // Get the mouse position and modifiers of this drag.
- SInt16 modifiers, mouseDownModifiers, mouseUpModifiers;
- ::GetDragModifiers(drag, &modifiers, &mouseDownModifiers, &mouseUpModifiers);
- MASK mask = LLWindowMacOSX::modifiersToMask(modifiers);
-
- Point mouse_point;
- // This will return the mouse point in global screen coords
- ::GetDragMouse(drag, &mouse_point, NULL);
- LLCoordScreen screen_coords(mouse_point.h, mouse_point.v);
+ float mouse_point[2];
+ // This will return the mouse point in window coords
+ getCursorPos(mWindow, mouse_point);
+ LLCoordWindow window_coords(mouse_point[0], mouse_point[1]);
LLCoordGL gl_pos;
- convertCoords(screen_coords, &gl_pos);
-
- // Look at the pasteboard and try to extract an URL from it
- PasteboardRef pasteboard;
- if(GetDragPasteboard(drag, &pasteboard) == noErr)
+ convertCoords(window_coords, &gl_pos);
+
+ if(!url.empty())
{
- ItemCount num_items = 0;
- // Treat an error here as an item count of 0
- (void)PasteboardGetItemCount(pasteboard, &num_items);
-
- // Only deal with single-item drags.
- if(num_items == 1)
- {
- PasteboardItemID item_id = NULL;
- CFArrayRef flavors = NULL;
- CFDataRef data = NULL;
-
- err = PasteboardGetItemIdentifier(pasteboard, 1, &item_id); // Yes, this really is 1-based.
-
- // Try to extract an URL from the pasteboard
- if(err == noErr)
- {
- err = PasteboardCopyItemFlavors( pasteboard, item_id, &flavors);
- }
-
- if(err == noErr)
- {
- if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeURL))
+ LLWindowCallbacks::DragNDropResult res =
+ mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url);
+
+ switch (res) {
+ case LLWindowCallbacks::DND_NONE: // No drop allowed
+ if (action == LLWindowCallbacks::DNDA_TRACK)
{
- // This is an URL.
- err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeURL, &data);
+ mDragOverrideCursor = 0;
}
- else if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeUTF8PlainText))
- {
- // This is a string that might be an URL.
- err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeUTF8PlainText, &data);
+ else {
+ mDragOverrideCursor = -1;
}
-
- }
-
- if(flavors != NULL)
- {
- CFRelease(flavors);
- }
-
- if(data != NULL)
- {
- std::string url;
- url.assign((char*)CFDataGetBytePtr(data), CFDataGetLength(data));
- CFRelease(data);
-
- if(!url.empty())
- {
- LLWindowCallbacks::DragNDropResult res =
- mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url);
-
- switch (res) {
- case LLWindowCallbacks::DND_NONE: // No drop allowed
- if (action == LLWindowCallbacks::DNDA_TRACK)
- {
- mDragOverrideCursor = kThemeNotAllowedCursor;
- }
- else {
- mDragOverrideCursor = -1;
- }
- break;
- case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation
- mDragOverrideCursor = kThemePointingHandCursor;
- result = noErr;
- break;
- case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation
- mDragOverrideCursor = kThemeCopyArrowCursor;
- result = noErr;
- break;
- case LLWindowCallbacks::DND_LINK: // Drop accepted would result in a "link" operation:
- mDragOverrideCursor = kThemeAliasArrowCursor;
- result = noErr;
- break;
- default:
- mDragOverrideCursor = -1;
- break;
- }
- // This overrides the cursor being set by setCursor.
- // This is a bit of a hack workaround because lots of areas
- // within the viewer just blindly set the cursor.
- if (mDragOverrideCursor == -1)
- {
- // Restore the cursor
- ECursorType temp_cursor = mCurrentCursor;
- // get around the "setting the same cursor" code in setCursor()
- mCurrentCursor = UI_CURSOR_COUNT;
- setCursor(temp_cursor);
- }
- else {
- // Override the cursor
- SetThemeCursor(mDragOverrideCursor);
- }
-
- }
- }
+ break;
+ case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation
+ mDragOverrideCursor = UI_CURSOR_NO;
+ break;
+ case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation
+ mDragOverrideCursor = UI_CURSOR_ARROWCOPY;
+ break;
+ default:
+ mDragOverrideCursor = -1;
+ break;
+ }
+ // This overrides the cursor being set by setCursor.
+ // This is a bit of a hack workaround because lots of areas
+ // within the viewer just blindly set the cursor.
+ if (mDragOverrideCursor == -1)
+ {
+ // Restore the cursor
+ ECursorType temp_cursor = mCurrentCursor;
+ // get around the "setting the same cursor" code in setCursor()
+ mCurrentCursor = UI_CURSOR_COUNT;
+ setCursor(temp_cursor);
+ }
+ else {
+ // Override the cursor
+ switch (mDragOverrideCursor) {
+ case 0:
+ setArrowCursor();
+ break;
+ case UI_CURSOR_NO:
+ setNotAllowedCursor();
+ case UI_CURSOR_ARROWCOPY:
+ setCopyCursor();
+ default:
+ break;
+ };
}
}
-
- return result;
}
#endif // LL_OS_DRAGDROP_ENABLED
diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h
index af83b50097..82195c2700 100755
--- a/indra/llwindow/llwindowmacosx.h
+++ b/indra/llwindow/llwindowmacosx.h
@@ -29,11 +29,12 @@
#include "llwindow.h"
#include "llwindowcallbacks.h"
+#include "llwindowmacosx-objc.h"
#include "lltimer.h"
-#include <Carbon/Carbon.h>
-#include <AGL/agl.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <OpenGL/OpenGL.h>
// AssertMacros.h does bad things.
#include "fix_macros.h"
@@ -106,7 +107,6 @@ public:
/*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b);
/*virtual*/ void *getPlatformWindow();
- /*virtual*/ void *getMediaWindow();
/*virtual*/ void bringToFront() {};
/*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b);
@@ -117,7 +117,17 @@ public:
// Provide native key event data
/*virtual*/ LLSD getNativeKeyData();
-
+
+ void* getWindow() { return mWindow; }
+ LLWindowCallbacks* getCallbacks() { return mCallbacks; }
+ LLPreeditor* getPreeditor() { return mPreeditor; }
+
+ void updateMouseDeltas(float* deltas);
+ void getMouseDeltas(float* delta);
+
+ void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action);
+
+ bool allowsLanguageInput() { return mLanguageTextInputAllowed; }
protected:
LLWindowMacOSX(LLWindowCallbacks* callbacks,
@@ -153,40 +163,34 @@ protected:
BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync);
void destroyContext();
void setupFailure(const std::string& text, const std::string& caption, U32 type);
- static pascal OSStatus staticEventHandler (EventHandlerCallRef myHandler, EventRef event, void* userData);
- static pascal Boolean staticMoveEventComparator( EventRef event, void* data);
- OSStatus eventHandler (EventHandlerCallRef myHandler, EventRef event);
void adjustCursorDecouple(bool warpingMouse = false);
void stopDockTileBounce();
- static MASK modifiersToMask(SInt16 modifiers);
+ static MASK modifiersToMask(S16 modifiers);
#if LL_OS_DRAGDROP_ENABLED
- static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow,
- void * handlerRefCon, DragRef theDrag);
- static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag);
- OSErr handleDragNDrop(DragRef theDrag, LLWindowCallbacks::DragNDropAction action);
+
+ //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag);
+ //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag);
+
+
#endif // LL_OS_DRAGDROP_ENABLED
//
// Platform specific variables
//
- WindowRef mWindow;
- AGLContext mContext;
- AGLPixelFormat mPixelFormat;
+
+ // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise.
+ NSWindowRef mWindow;
+ GLViewRef mGLView;
+ CGLContextObj mContext;
+ CGLPixelFormatObj mPixelFormat;
CGDirectDisplayID mDisplay;
- CFDictionaryRef mOldDisplayMode;
- EventLoopTimerRef mTimer;
- EventHandlerUPP mEventHandlerUPP;
- EventHandlerRef mGlobalHandlerRef;
- EventHandlerRef mWindowHandlerRef;
- EventComparatorUPP mMoveEventCampartorUPP;
- Rect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
- Rect mPreviousWindowRect; // Save previous window for un-maximize event
- Str255 mWindowTitle;
+ LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse()
+ std::string mWindowTitle;
double mOriginalAspectRatio;
BOOL mSimulatedRightClick;
- UInt32 mLastModifiers;
+ U32 mLastModifiers;
BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing.
// Used to allow event processing when putting up dialogs in fullscreen mode.
BOOL mCursorDecoupled;
@@ -201,25 +205,20 @@ protected:
U32 mFSAASamples;
BOOL mForceRebuild;
- S32 mDragOverrideCursor;
+ S32 mDragOverrideCursor;
F32 mBounceTime;
- NMRec mBounceRec;
+ //NMRec mBounceRec;
LLTimer mBounceTimer;
// Input method management through Text Service Manager.
- TSMDocumentID mTSMDocument;
BOOL mLanguageTextInputAllowed;
- ScriptCode mTSMScriptCode;
- LangCode mTSMLangCode;
LLPreeditor* mPreeditor;
static BOOL sUseMultGL;
friend class LLWindowManager;
- static WindowRef sMediaWindow;
- EventRef mRawKeyEvent;
-
+
};