root/OpenSceneGraph/trunk/src/osgViewer/GraphicsWindowCocoa.mm @ 10285

Revision 10285, 48.8 kB (checked in by robert, 6 years ago)

From Stephan Huber, "attached you'll find a small fix for GrphicsWindowCocoa?. There was a bug
with certain key-strokes, which led to a crash."

  • Property svn:executable set to *
RevLine 
[9879]1/*
2 *  GraphicsWindowCocoa.cpp
3 *  OpenSceneGraph
4 *
5 *  Created by Stephan Huber on 27.06.08.
6 *  Copyright 2008 Stephan Maximilian Huber, digital mind. All rights reserved.
7 *
8 *  Some code borrowed from the implementation of CocoaViewer,
9 *  Created by Eric Wing on 11/12/06. and ported by Martin Lavery 7/06/07
[10208]10 *
11 *  Other snippets are borrowed from the Cocoa-implementation of the SDL-lib
[9879]12 */
13
14#include <iostream>
15#include <osgViewer/api/Cocoa/PixelBufferCocoa>
16#include <osgViewer/api/Cocoa/GraphicsWindowCocoa>
17
18#include <Cocoa/Cocoa.h>
19
20#include "DarwinUtils.h"
21
[10208]22//#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl;
[9879]23
[10208]24#define DEBUG_OUT(s) ;
25
[9879]26static bool s_quit_requested = false;
27
[10208]28#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
29@interface NSApplication(NSAppleMenu)
30- (void)setAppleMenu:(NSMenu *)menu;
31@end
32#endif
[9879]33
[10208]34
[9879]35// ----------------------------------------------------------------------------------------------------------
36// small helper class remapping key-codes
37// ----------------------------------------------------------------------------------------------------------
38// small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys
39
40class CocoaKeyboardMap {
41
42    public:
43        CocoaKeyboardMap()
44        {
45            _keymap[27]     = osgGA::GUIEventAdapter::KEY_Escape;
46            _keymap[13]     = osgGA::GUIEventAdapter::KEY_KP_Enter;
47            _keymap[3]      = osgGA::GUIEventAdapter::KEY_Return;
48            _keymap[9]      = osgGA::GUIEventAdapter::KEY_Tab;
49            _keymap[32]     = osgGA::GUIEventAdapter::KEY_Space;
50            _keymap[127]    = osgGA::GUIEventAdapter::KEY_BackSpace;
51           
52           
53            _keymap[NSHomeFunctionKey]          = osgGA::GUIEventAdapter::KEY_Home;
54            _keymap[NSEndFunctionKey]           = osgGA::GUIEventAdapter::KEY_End;
55            _keymap[NSPageUpFunctionKey]        = osgGA::GUIEventAdapter::KEY_Page_Up;
56            _keymap[NSPageDownFunctionKey]      = osgGA::GUIEventAdapter::KEY_Page_Down;
57            _keymap[NSLeftArrowFunctionKey]     = osgGA::GUIEventAdapter::KEY_Left;
58            _keymap[NSRightArrowFunctionKey]    = osgGA::GUIEventAdapter::KEY_Right;
59            _keymap[NSUpArrowFunctionKey]       = osgGA::GUIEventAdapter::KEY_Up;
60            _keymap[NSDownArrowFunctionKey]     = osgGA::GUIEventAdapter::KEY_Down;
61           
62            _keymap[NSDeleteFunctionKey]        = osgGA::GUIEventAdapter::KEY_Delete;
63           
64            _keymap[NSF1FunctionKey]  = osgGA::GUIEventAdapter::KEY_F1;
65            _keymap[NSF2FunctionKey]  = osgGA::GUIEventAdapter::KEY_F2;
66            _keymap[NSF3FunctionKey]  = osgGA::GUIEventAdapter::KEY_F3;
67            _keymap[NSF4FunctionKey]  = osgGA::GUIEventAdapter::KEY_F4;
68            _keymap[NSF5FunctionKey]  = osgGA::GUIEventAdapter::KEY_F5;
69            _keymap[NSF6FunctionKey]  = osgGA::GUIEventAdapter::KEY_F6;
70            _keymap[NSF7FunctionKey]  = osgGA::GUIEventAdapter::KEY_F7;
71            _keymap[NSF8FunctionKey]  = osgGA::GUIEventAdapter::KEY_F8;
72            _keymap[NSF9FunctionKey]  = osgGA::GUIEventAdapter::KEY_F9;
73           
74            _keymap[NSF10FunctionKey]  = osgGA::GUIEventAdapter::KEY_F10;
75            _keymap[NSF11FunctionKey]  = osgGA::GUIEventAdapter::KEY_F11;
76            _keymap[NSF12FunctionKey]  = osgGA::GUIEventAdapter::KEY_F12;
77            _keymap[NSF13FunctionKey]  = osgGA::GUIEventAdapter::KEY_F13;
78            _keymap[NSF14FunctionKey]  = osgGA::GUIEventAdapter::KEY_F14;
79            _keymap[NSF15FunctionKey]  = osgGA::GUIEventAdapter::KEY_F15;
80            _keymap[NSF16FunctionKey]  = osgGA::GUIEventAdapter::KEY_F16;
81            _keymap[NSF17FunctionKey]  = osgGA::GUIEventAdapter::KEY_F17;
82            _keymap[NSF18FunctionKey]  = osgGA::GUIEventAdapter::KEY_F18;
83            _keymap[NSF19FunctionKey]  = osgGA::GUIEventAdapter::KEY_F19;
84           
85            _keymap[NSF20FunctionKey]  = osgGA::GUIEventAdapter::KEY_F20;
86            _keymap[NSF21FunctionKey]  = osgGA::GUIEventAdapter::KEY_F21;
87            _keymap[NSF22FunctionKey]  = osgGA::GUIEventAdapter::KEY_F22;
88            _keymap[NSF23FunctionKey]  = osgGA::GUIEventAdapter::KEY_F23;
89            _keymap[NSF24FunctionKey]  = osgGA::GUIEventAdapter::KEY_F24;
90            _keymap[NSF25FunctionKey]  = osgGA::GUIEventAdapter::KEY_F25;
91            _keymap[NSF26FunctionKey]  = osgGA::GUIEventAdapter::KEY_F26;
92            _keymap[NSF27FunctionKey]  = osgGA::GUIEventAdapter::KEY_F27;
93            _keymap[NSF28FunctionKey]  = osgGA::GUIEventAdapter::KEY_F28;
94            _keymap[NSF29FunctionKey]  = osgGA::GUIEventAdapter::KEY_F29;
95           
96            _keymap[NSF30FunctionKey]  = osgGA::GUIEventAdapter::KEY_F30;
97            _keymap[NSF31FunctionKey]  = osgGA::GUIEventAdapter::KEY_F31;
98            _keymap[NSF32FunctionKey]  = osgGA::GUIEventAdapter::KEY_F32;
99            _keymap[NSF33FunctionKey]  = osgGA::GUIEventAdapter::KEY_F33;
100            _keymap[NSF34FunctionKey]  = osgGA::GUIEventAdapter::KEY_F34;
101            _keymap[NSF35FunctionKey]  = osgGA::GUIEventAdapter::KEY_F35;
102                       
103           
104            _keypadmap['='] = osgGA::GUIEventAdapter::KEY_KP_Equal;
105            _keypadmap['*'] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
106            _keypadmap['+'] = osgGA::GUIEventAdapter::KEY_KP_Add;
107            _keypadmap['-'] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
108            _keypadmap['.'] = osgGA::GUIEventAdapter::KEY_KP_Decimal;
109            _keypadmap['/'] = osgGA::GUIEventAdapter::KEY_KP_Divide;
110           
111            _keypadmap['0'] = osgGA::GUIEventAdapter::KEY_KP_0;
112            _keypadmap['1'] = osgGA::GUIEventAdapter::KEY_KP_1;
113            _keypadmap['2'] = osgGA::GUIEventAdapter::KEY_KP_2;
114            _keypadmap['3'] = osgGA::GUIEventAdapter::KEY_KP_3;
115            _keypadmap['4'] = osgGA::GUIEventAdapter::KEY_KP_4;
116            _keypadmap['5'] = osgGA::GUIEventAdapter::KEY_KP_5;
117            _keypadmap['6'] = osgGA::GUIEventAdapter::KEY_KP_6;
118            _keypadmap['7'] = osgGA::GUIEventAdapter::KEY_KP_7;
119            _keypadmap['8'] = osgGA::GUIEventAdapter::KEY_KP_8;
120            _keypadmap['9'] = osgGA::GUIEventAdapter::KEY_KP_9;
121        }
122       
123        ~CocoaKeyboardMap() {
124        }
125       
126        unsigned int remapKey(unsigned int key, bool pressedOnKeypad = false)
127        {
128            if (pressedOnKeypad) {
129                 KeyMap::iterator itr = _keypadmap.find(key);
130                if (itr == _keypadmap.end()) return key;
131                else return itr->second;
132            }
133           
134            KeyMap::iterator itr = _keymap.find(key);
135            if (itr == _keymap.end()) return key;
136            else return itr->second;
137        }
138    private:
139        typedef std::map<unsigned int, osgGA::GUIEventAdapter::KeySymbol> KeyMap;
140        KeyMap _keymap, _keypadmap;
141};
142
143
144// ----------------------------------------------------------------------------------------------------------
145// remapCocoaKey
146// ----------------------------------------------------------------------------------------------------------
147static unsigned int remapCocoaKey(unsigned int key, bool pressedOnKeypad = false)
148{
149    static CocoaKeyboardMap s_CocoaKeyboardMap;
150    return s_CocoaKeyboardMap.remapKey(key, pressedOnKeypad);
151}
152
153
154std::ostream& operator<<(std::ostream& os, const NSRect& rect)
155{
[9895]156    os << rect.origin.x << "/" << rect.origin.y << " " << rect.size.width << "x" << rect.size.height;
157    return os;
[9879]158}
159
160// ----------------------------------------------------------------------------------------------------------
161// Cocoa uses a coordinate system where its origin is in the bottom left corner,
162// osg and quartz uses top left for the origin
163//
164// these 2 methods convets rects between the different coordinate systems
165// ----------------------------------------------------------------------------------------------------------
166
167static NSRect convertFromQuartzCoordinates(const NSRect& rect) 
168{
169    NSRect frame = [[[NSScreen screens] objectAtIndex: 0] frame];
170    float y = frame.size.height - rect.origin.y - rect.size.height;
[9895]171    NSRect converted = NSMakeRect(rect.origin.x, y, rect.size.width, rect.size.height);
172   
173    // std::cout << "converting from Quartz " << rect << " to " << converted << " using screen rect " << frame << std::endl;
174   
[9879]175    return converted;
176}
177
178static NSRect convertToQuartzCoordinates(const NSRect& rect)
179{
180    NSRect frame = [[[NSScreen screens] objectAtIndex: 0] frame];
181   
182    float y = frame.size.height - (rect.origin.y + rect.size.height);
[9895]183    NSRect converted = NSMakeRect(rect.origin.x, y, rect.size.width, rect.size.height);
184   
185    // std::cout << "converting To Quartz   " << rect << " to " << converted << " using screen rect " << frame << std::endl;
186   
[9879]187    return converted;
188}
189
190#pragma mark CocoaAppDelegate
191
192// ----------------------------------------------------------------------------------------------------------
193// the app-delegate, handling quit-requests
194// ----------------------------------------------------------------------------------------------------------
195
196@interface CocoaAppDelegate : NSObject 
197{
198}
199
200- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
[10208]201- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
[9879]202@end
203
204@implementation CocoaAppDelegate
205- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
206{
207    s_quit_requested = true;
[10208]208    DEBUG_OUT("quit requested ");
209    return NSTerminateCancel;
[9879]210}
211
[10208]212- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
213{
214    DEBUG_OUT("applicationDidFinishLaunching");
215}
216
[9879]217@end
218
219#pragma mark GraphicsWindowCocoaWindow
220
221// ----------------------------------------------------------------------------------------------------------
222// GraphicsWindowCocoaWindow, implements canBecomeKeyWindow + canBecomeMainWindow
223// ----------------------------------------------------------------------------------------------------------
224
225@interface GraphicsWindowCocoaWindow : NSWindow
226{
227}
228
229- (BOOL) canBecomeKeyWindow;
230- (BOOL) canBecomeMainWindow;
231
232@end
233
234@implementation GraphicsWindowCocoaWindow
235
236
237- (BOOL) canBecomeKeyWindow
238{
239    return YES;
240}
241
242- (BOOL) canBecomeMainWindow
243{
244    return YES;
245}
246
247@end
248
249#pragma mark GraphicsWindowCocoaGLView
250
251
252// ----------------------------------------------------------------------------------------------------------
253// GraphicsWindowCocoaGLView
254// custom NSOpenGLView-class handling mouse- and keyboard-events, forwarding them to the EventQueue
255// some code borrowed from the example osgCocoaViewer from E.Wing
256// ----------------------------------------------------------------------------------------------------------
257
258@interface GraphicsWindowCocoaGLView : NSOpenGLView
259{
260    @private
261        osgViewer::GraphicsWindowCocoa* _win;
262        BOOL _isUsingCtrlClick, _isUsingOptionClick;
263        unsigned int _cachedModifierFlags;
[9895]264        BOOL _handleTabletEvents;
[9879]265       
266}
267- (void)setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win;
268
269- (void)keyDown:(NSEvent *)theEvent;
270- (void)keyUp:(NSEvent *)theEvent;
271- (void)flagsChanged:(NSEvent *)theEvent;
272- (void) mouseMoved:(NSEvent*)theEvent;
273- (void) mouseDown:(NSEvent*)theEvent;
274- (void) mouseDragged:(NSEvent*)theEvent;
275- (void) mouseUp:(NSEvent*)theEvent;
276- (void) rightMouseDown:(NSEvent*)theEvent;
277- (void) rightMouseDragged:(NSEvent*)theEvent;
278- (void) rightMouseUp:(NSEvent*)theEvent;
279- (void) otherMouseDown:(NSEvent*)theEvent;
280- (void) otherMouseDragged:(NSEvent*)theEvent;
281- (void) otherMouseUp:(NSEvent*)theEvent;
282
283- (NSPoint) getLocalPoint: (NSEvent*)theEvent;
284- (void) handleModifiers: (NSEvent*)theEvent;
285- (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click;
286- (BOOL) isUsingCtrlClick;
287- (void) setIsUsingOptionClick:(BOOL)is_using_option_click;
288- (BOOL) isUsingOptionClick;
289
290- (void) doLeftMouseButtonDown:(NSEvent*)theEvent;
291- (void) doLeftMouseButtonUp:(NSEvent*)theEvent;
292- (void) doRightMouseButtonDown:(NSEvent*)theEvent;
293- (void) doRightMouseButtonUp:(NSEvent*)theEvent;
294- (void) doMiddleMouseButtonDown:(NSEvent*)theEvent;
295- (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number;
296- (void) doMiddleMouseButtonUp:(NSEvent*)theEvent;
297- (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number;
298- (void) scrollWheel:(NSEvent*)theEvent;
299
300- (void)tabletPoint:(NSEvent *)theEvent;
301- (void)tabletProximity:(NSEvent *)theEvent;
302- (void)handleTabletEvents:(NSEvent*)theEvent;
303
304- (BOOL)acceptsFirstResponder;
305- (BOOL)becomeFirstResponder;
306- (BOOL)resignFirstResponder;
307
308@end
309
310@implementation GraphicsWindowCocoaGLView 
311
312
313-(void) setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win
314{
315    _win = win;
316}
317
318- (BOOL)acceptsFirstResponder
319{
320  return YES;
321}
322
323- (BOOL)becomeFirstResponder
324{
325  return YES;
326}
327
328- (BOOL)resignFirstResponder
329{
330  return YES;
331}
332
333
334- (NSPoint) getLocalPoint: (NSEvent*)theEvent
335{
336    return  [self convertPoint:[theEvent locationInWindow] fromView:nil];
337}
338
339
340- (void) handleModifiers: (NSEvent*)theEvent
341{
[10208]342    DEBUG_OUT("handling modifiers");
343   
344    if ((!_win) || (!_win->getEventQueue()))
345        return; // no event    queue in place
346   
[9879]347    unsigned int flags = [theEvent modifierFlags];
348   
349    if (flags == _cachedModifierFlags)
350        return;
351   
352    const unsigned int masks[] = {
353        NSShiftKeyMask,
354        NSControlKeyMask,
355        NSAlternateKeyMask,
356        NSCommandKeyMask,
357        NSAlphaShiftKeyMask
358    };
359   
360    const unsigned int keys[] = {
361        osgGA::GUIEventAdapter::KEY_Shift_L,
362        osgGA::GUIEventAdapter::KEY_Control_L,
363        osgGA::GUIEventAdapter::KEY_Alt_L,
364        osgGA::GUIEventAdapter::KEY_Super_L,
365        osgGA::GUIEventAdapter::KEY_Caps_Lock
366    };
367   
368    for(unsigned int i = 0; i < 5; ++i) {
369       
370        if ((flags & masks[i]) && !(_cachedModifierFlags & masks[i]))
371        {
372            _win->getEventQueue()->keyPress(keys[i]);
373        }
374       
375        if (!(flags & masks[i]) && (_cachedModifierFlags & masks[i]))
376        {
377            _win->getEventQueue()->keyRelease(keys[i]);
378        }
379    }
380   
381    _cachedModifierFlags = flags;
382   
383}
384
385- (void)flagsChanged:(NSEvent *)theEvent {
[9895]386    [self handleModifiers: theEvent];
[9879]387}
388
389- (void) mouseMoved:(NSEvent*)theEvent 
390{
[10208]391    DEBUG_OUT("Mouse moved");
[9879]392    NSPoint converted_point = [self getLocalPoint: theEvent];
393    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
394}
395
396
397
398- (void) mouseDown:(NSEvent*)theEvent
399{
[10208]400    DEBUG_OUT("Mouse down");
[9879]401    // Because many Mac users have only a 1-button mouse, we should provide ways
402    // to access the button 2 and 3 actions of osgViewer.
403    // I will use the Ctrl modifer to represent right-clicking
404    // and Option modifier to represent middle clicking.
405    if([theEvent modifierFlags] & NSControlKeyMask)
406    {
407        [self setIsUsingCtrlClick:YES];
408        [self doRightMouseButtonDown:theEvent];
409    }
410    else if([theEvent modifierFlags] & NSAlternateKeyMask)
411    {
412        [self setIsUsingOptionClick:YES];
413        [self doMiddleMouseButtonDown:theEvent];
414    }
415    else
416    {
417        [self doLeftMouseButtonDown:theEvent];
418    }
[9895]419   
420    if ([theEvent subtype] == NSTabletPointEventSubtype) {
421        _handleTabletEvents = true;
422        [self handleTabletEvents:theEvent];
423    }
[9879]424}
425
426
427- (void) mouseDragged:(NSEvent*)theEvent
428{
[10208]429    if (!_win) return;
430   
[9879]431    NSPoint converted_point = [self getLocalPoint: theEvent];   
432    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
[9895]433   
434    if (_handleTabletEvents)
435        [self handleTabletEvents:theEvent];
[9879]436}
437
438
439- (void) mouseUp:(NSEvent*)theEvent
440{
441    // Because many Mac users have only a 1-button mouse, we should provide ways
442    // to access the button 2 and 3 actions of osgViewer.
443    // I will use the Ctrl modifer to represent right-clicking
444    // and Option modifier to represent middle clicking.
445    if([self isUsingCtrlClick] == YES)
446    {
447        [self setIsUsingCtrlClick:NO];
448        [self doRightMouseButtonUp:theEvent];
449    }
450    else if([self isUsingOptionClick] == YES)
451    {
452        [self setIsUsingOptionClick:NO];
453        [self doMiddleMouseButtonUp:theEvent];
454    }
455    else
456    {
457        [self doLeftMouseButtonUp:theEvent];
458    }
[9895]459    _handleTabletEvents = false;
[9879]460}
461
462- (void) rightMouseDown:(NSEvent*)theEvent
463{
464    [self doRightMouseButtonDown:theEvent];
465}
466
467- (void) rightMouseDragged:(NSEvent*)theEvent
468{
[10208]469    if (!_win) return;
470   
[9879]471    NSPoint converted_point = [self getLocalPoint: theEvent];
472    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
473}
474
475- (void) rightMouseUp:(NSEvent*)theEvent
476{
477    [self doRightMouseButtonUp:theEvent];
[9895]478    _handleTabletEvents = false;
[9879]479}
480
481// "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc).
482- (void) otherMouseDown:(NSEvent*)theEvent
483{
484    // Button 0 is left
485    // Button 1 is right
486    // Button 2 is middle
487    // Button 3 keeps going
488    // osgViewer expects 1 for left, 3 for right, 2 for middle
489    // osgViewer has a reversed number mapping for right and middle compared to Cocoa
490    if([theEvent buttonNumber] == 2)
491    {
492        [self doMiddleMouseButtonDown:theEvent];
493    }
494    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer
495    {
496        [self doExtraMouseButtonDown:theEvent buttonNumber:[theEvent buttonNumber]];
497    }
498}
499
500- (void) otherMouseDragged:(NSEvent*)theEvent
501{
[10208]502    if (!_win) return;
503   
[9879]504    NSPoint converted_point = [self getLocalPoint: theEvent];   
505    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
506   
507}
508
509// "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc).
510- (void) otherMouseUp:(NSEvent*)theEvent
511{
512   
513    // Button 0 is left
514    // Button 1 is right
515    // Button 2 is middle
516    // Button 3 keeps going
517    // osgViewer expects 1 for left, 3 for right, 2 for middle
518    // osgViewer has a reversed number mapping for right and middle compared to Cocoa
519    if([theEvent buttonNumber] == 2)
520    {
521        [self doMiddleMouseButtonUp:theEvent];
522    }
523    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer
524    {
525        // I don't think osgViewer does anything for these additional buttons,
526        // but just in case, pass them along. But as a Cocoa programmer, you might
527        // think about things you can do natively here instead of passing the buck.
528        [self doExtraMouseButtonUp:theEvent buttonNumber:[theEvent buttonNumber]];
529    }
530}
531
532- (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click
533{
534    _isUsingCtrlClick = is_using_ctrl_click;
535}
536
537- (BOOL) isUsingCtrlClick
538{
539    return _isUsingCtrlClick;
540}
541
542- (void) setIsUsingOptionClick:(BOOL)is_using_option_click
543{
544    _isUsingOptionClick = is_using_option_click;
545}
546
547- (BOOL) isUsingOptionClick
548{
549    return _isUsingOptionClick;
550}
551
552
553- (void) doLeftMouseButtonDown:(NSEvent*)theEvent
554{
[10208]555    if (!_win) return;
556   
[9879]557    NSPoint converted_point = [self getLocalPoint: theEvent];
558   
559    if([theEvent clickCount] == 1)
560    {
561        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1);
562    }
563    else
564    {
565        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 1);
566    }
567}
568
569- (void) doLeftMouseButtonUp:(NSEvent*)theEvent
570{
[10208]571    if (!_win) return;
572   
[9879]573    NSPoint converted_point = [self getLocalPoint: theEvent];
574   
575    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 1);
576
577}
578
579- (void) doRightMouseButtonDown:(NSEvent*)theEvent
580{
[10208]581    if (!_win) return;
582   
[9879]583    NSPoint converted_point = [self getLocalPoint: theEvent];
584    if([theEvent clickCount] == 1)
585    {
586        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 3);
587    }
588    else
589    {
590        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 3);
591    }
592
593}
594
595
596- (void) doRightMouseButtonUp:(NSEvent*)theEvent
597{
[10208]598    if (!_win) return;
599   
[9879]600    NSPoint converted_point = [self getLocalPoint: theEvent];   
601    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 3);
602}
603
604- (void) doMiddleMouseButtonDown:(NSEvent*)theEvent
605{
[10208]606    if (!_win) return;
607   
[9879]608    NSPoint converted_point = [self getLocalPoint: theEvent];
609   
610    if([theEvent clickCount] == 1)
611    {
612        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 2);
613    }
614    else
615    {
616        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 2);
617    }
618}
619
620- (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number
621{
[10208]622    if (!_win) return;
623   
[9879]624    NSPoint converted_point = [self getLocalPoint: theEvent];
625    if([theEvent clickCount] == 1)
626    {
627        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1);
628    }
629    else
630    {
631        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, button_number+1);
632    }
633}
634
635
636- (void) doMiddleMouseButtonUp:(NSEvent*)theEvent
637{
[10208]638    if (!_win) return;
639   
[9879]640    NSPoint converted_point = [self getLocalPoint: theEvent];
641    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2);
642
643}
644
645- (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number
646{
[10208]647    if (!_win) return;
648   
[9879]649    NSPoint converted_point = [self getLocalPoint: theEvent];
650    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1);
651}
652
653
654
655- (void) scrollWheel:(NSEvent*)theEvent
656{
[10208]657    if (!_win) return;
658   
[9879]659    // Unfortunately, it turns out mouseScroll2D doesn't actually do anything.
660    // The camera manipulators don't seem to implement any code that utilize the scroll values.
661    // This this call does nothing.
662    _win->getEventQueue()->mouseScroll2D([theEvent deltaX], [theEvent deltaY]);
663}
664
665
666
667- (void)keyDown:(NSEvent *)theEvent 
668{
[10208]669    if (!_win) return;
670   
[9879]671    NSString* chars = [theEvent charactersIgnoringModifiers];
[10285]672    if ((chars) && ([chars length] > 0)) {
673        unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask) );
674        // std::cout << "key dn: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
675        _win->getEventQueue()->keyPress( remapCocoaKey(keyCode), [theEvent timestamp]);
676    }
[9879]677}
678
679
680- (void)keyUp:(NSEvent *)theEvent 
681{   
[10208]682    if (!_win) return;
683   
[9879]684    NSString* chars = [theEvent charactersIgnoringModifiers];
[10285]685    if ((chars) && ([chars length] > 0)) {
686        unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask));
687        // std::cout << "key up: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
688        _win->getEventQueue()->keyRelease( remapCocoaKey(keyCode), [theEvent timestamp]);
689    }
[9879]690}
691
692
693- (void)tabletPoint:(NSEvent *)theEvent
694{
[9895]695    //_handleTabletEvents = YES;
696    //[self handleTabletEvents:theEvent];
[9879]697}
698
699-(void)handleTabletEvents:(NSEvent *)theEvent
700{
[10208]701    if (!_win) return;
702   
[9895]703    float pressure = [theEvent pressure];
704    _win->getEventQueue()->penPressure(pressure);
705    NSPoint tilt = [theEvent tilt];
706   
707    _win->getEventQueue()->penOrientation (tilt.x, tilt.y, [theEvent rotation]);
[9879]708}
709
710
711- (void)tabletProximity:(NSEvent *)theEvent
712{
[10208]713    if (!_win) return;
714   
[9895]715    osgGA::GUIEventAdapter::TabletPointerType pt(osgGA::GUIEventAdapter::UNKNOWN);
716    switch ([theEvent pointingDeviceType]) {
717        case NSPenPointingDevice:
718            pt = osgGA::GUIEventAdapter::PEN;
719            break;
720        case NSCursorPointingDevice:
721            pt = osgGA::GUIEventAdapter::PUCK;
722            break;
723        case NSEraserPointingDevice:
724            pt = osgGA::GUIEventAdapter::ERASER;
725            break;
726        default:
727            break;
728    }
729    _win->getEventQueue()->penProximity(pt, [theEvent isEnteringProximity]);
[9879]730}
731
732
733@end
734
735
736#pragma mark GraphicsWindowCocoaDelegate
737
738
739// ----------------------------------------------------------------------------------------------------------
740// the window-delegate, handles moving/resizing of the window etc.
741// ----------------------------------------------------------------------------------------------------------
742
743@interface GraphicsWindowCocoaDelegate : NSObject
744{
745    @private
746        osgViewer::GraphicsWindowCocoa* _win;
747        BOOL                            _inDidMove;
748}
749
750- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win;
751- (void)windowDidMove:(NSNotification *)notification;
752- (void)windowDidResize:(NSNotification *)notification;
753- (BOOL)windowShouldClose:(id)window;
754- (void)updateWindowBounds;
755
756@end
757
758
759@implementation GraphicsWindowCocoaDelegate
760
761- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win
762{
763    _inDidMove = false;
764    _win = win;
765    return [super init];
766}
767
768
769- (void)windowDidMove:(NSNotification *)notification
770{
771    [self updateWindowBounds];
772}
773
774- (void)windowDidResize:(NSNotification *)notification
775{
776    [self updateWindowBounds];
777}
778
779-(void)updateWindowBounds
780{
781    if (_inDidMove) return;
782    _inDidMove = true;
783   
784    GraphicsWindowCocoaWindow* nswin = _win->getWindow();
785    NSRect bounds = [nswin contentRectForFrameRect: [nswin frame] ];
786   
787    // convert to quartz-coordinate-system
788    bounds = convertToQuartzCoordinates(bounds);
789   
790    // std::cout << "windowdidmove: " << bounds.origin.x << " " << bounds.origin.y << " " << bounds.size.width << " " << bounds.size.height << std::endl;
791   
792    _win->adaptResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
793    //_win->getEventQueue()->windowResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height, _win->getEventQueue()->getTime());
794    _win->requestRedraw();
795    _inDidMove = false;
796}
797
798- (BOOL)windowShouldClose:(id)window 
799{
800    return _win->requestClose();
801}
802
803@end
804
805
806#pragma mark CocoaWindowAdapter
807
808
809
810using namespace osgDarwin;
811namespace osgViewer {
812
813
814// ----------------------------------------------------------------------------------------------------------
815// small adapter class to handle the dock/menubar
816// ----------------------------------------------------------------------------------------------------------
817
818class CocoaWindowAdapter : public MenubarController::WindowAdapter {
819public:
820    CocoaWindowAdapter(GraphicsWindowCocoa* win) : MenubarController::WindowAdapter(), _win(win) {}
821   
822    virtual bool valid() { return (_win.valid() && _win->valid()); }
[9895]823   
[9879]824    virtual void getWindowBounds(CGRect& rect)
825    {
826        NSRect nsrect = [_win->getWindow() frame];
827        nsrect = convertToQuartzCoordinates(nsrect);
828       
829        rect.origin.x = nsrect.origin.x;
830        rect.origin.y = nsrect.origin.y;
831        rect.size.width = nsrect.size.width;
832        rect.size.height = nsrect.size.height;
833    }
[9895]834   
[9879]835    virtual osgViewer::GraphicsWindow* getWindow() {return _win.get(); }
836private:
837    osg::observer_ptr<GraphicsWindowCocoa> _win;
838};
839
840#pragma mark GraphicsWindowCocoa
841
842
843
844// ----------------------------------------------------------------------------------------------------------
845// init
846// ----------------------------------------------------------------------------------------------------------
847
848void GraphicsWindowCocoa::init()
849{
850    if (_initialized) return;
851
852    _closeRequested = false;
853    _ownsWindow = false;
854    _context = NULL;
855    _window = NULL;
856    _valid = _initialized = true;
857}
858
859
860// ----------------------------------------------------------------------------------------------------------
861// setupNSWindow
862// sets up the NSWindow, adds delegates, etc
863// ----------------------------------------------------------------------------------------------------------
864
865void GraphicsWindowCocoa::setupNSWindow(NSWindow* win)
866{
867
868    [win setReleasedWhenClosed:NO];
[9895]869    [win setDisplaysWhenScreenProfileChanges:YES];   
[9879]870    GraphicsWindowCocoaDelegate* delegate = [[GraphicsWindowCocoaDelegate alloc] initWith: this];
871    [win setDelegate: delegate ];
872    //[delegate autorelease];
[9895]873       
[9879]874    [win makeKeyAndOrderFront:nil];
875    [win setAcceptsMouseMovedEvents: YES];
876
877}
878
879
880// ----------------------------------------------------------------------------------------------------------
881// realizeImplementation, creates the window + context
882// ----------------------------------------------------------------------------------------------------------
883
884bool GraphicsWindowCocoa::realizeImplementation()
885{
886    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
887   
888    unsigned int style(NSBorderlessWindowMask);
889   
890    if (_traits->windowDecoration) {
891        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
892       
893        // supportsResize works only with windows with titlebar
894        if (_traits->supportsResize)
895            style |= NSResizableWindowMask;
896    }
[9895]897       
[9879]898    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
899    int screenLeft(0), screenTop(0);
900    if (wsi) {
901        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
902    }
903   
[9895]904    NSRect rect = NSMakeRect(_traits->x + screenLeft, _traits->y + screenTop, _traits->width, _traits->height);
[9879]905   
[10208]906    _ownsWindow = true;
[9895]907   
[10208]908    // should we create a NSView only??
909    WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : NULL;
910    if (windowData)
911    {
912        if (windowData->createOnlyView())
913            _ownsWindow = false;
914        _checkForEvents = windowData->checkForEvents();
915       
916    }
[9879]917   
[10208]918
919    osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / ownsWindow: " << _ownsWindow << " checkForEvents: " << _checkForEvents << std::endl;
920
921    if (_ownsWindow)
922    {
923        _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
924       
925        if (!_window) {
926            osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl;
927            return false;
928        }
929
930        rect = convertFromQuartzCoordinates(rect);
931        [_window setFrameOrigin: rect.origin];
932    }
933           
[9895]934    NSOpenGLPixelFormatAttribute attr[32];
[9879]935    int i = 0;
936   
937    attr[i++] = NSOpenGLPFADepthSize;
938    attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->depth);
939
940    if (_traits->doubleBuffer) {
941        attr[i++] = NSOpenGLPFADoubleBuffer;
942    }
943   
944    if (_traits->alpha) {
945        attr[i++] = NSOpenGLPFAAlphaSize;
946        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->alpha);
947    }
948
949    if (_traits->stencil) {
950        attr[i++] = NSOpenGLPFAStencilSize;
951        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->stencil);
952    }
953 
954
955    if (_traits->sampleBuffers) {
956        attr[i++] = NSOpenGLPFASampleBuffers;
957        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->sampleBuffers);
958        attr[i++] = NSOpenGLPFASamples;
959        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->samples);
960    }
961
962   
963    attr[i++] = NSOpenGLPFAAccelerated;
964    attr[i] = static_cast<NSOpenGLPixelFormatAttribute>(0);
965   
966    // create the context
967    NSOpenGLContext* sharedContext = NULL;
968   
969    GraphicsWindowCocoa* graphicsWindowCocoa = dynamic_cast<GraphicsWindowCocoa*>(_traits->sharedContext);
970    if (graphicsWindowCocoa)
971    {
972        sharedContext = graphicsWindowCocoa->getContext();
973    }
974    else
975    {
976        PixelBufferCocoa* pixelbuffer = dynamic_cast<PixelBufferCocoa*>(_traits->sharedContext);
977        if (pixelbuffer) {
978            sharedContext = pixelbuffer->getContext();
979        }
980    }
[9895]981   
982    NSOpenGLPixelFormat* pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ];
[9879]983    _context = [[NSOpenGLContext alloc] initWithFormat: pixelformat shareContext: sharedContext];
984   
985    if (!_context) {
986        osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create context" << std::endl;
987        return false;
988    }
[9895]989    GraphicsWindowCocoaGLView* theView = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ];
[9879]990    [theView setAutoresizingMask:  (NSViewWidthSizable | NSViewHeightSizable) ];
991    [theView setGraphicsWindowCocoa: this];
992    [theView setOpenGLContext:_context];
[10208]993    _view = theView;
994    osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / view: " << theView << std::endl;
995
996    if (_ownsWindow) {
997        [_window setContentView: theView];
998        setupNSWindow(_window);
999        [theView release];
1000       
1001        MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) );
1002    }
1003    else 
1004    {
1005        windowData->setCreatedNSView(theView);
1006    }
1007
[9879]1008    [pool release];
[9895]1009   
[9879]1010   
1011    useCursor(_traits->useCursor);
1012    setWindowName(_traits->windowName);
1013    setVSync(_traits->vsync);
1014   
1015    MenubarController::instance()->update();
1016   
1017    // Cocoa's origin is bottom/left:
1018    getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
1019   
1020    _valid = _initialized = _realized = true;
1021    return _valid;
1022}
1023
1024
1025
1026
1027// ----------------------------------------------------------------------------------------------------------
1028// closeImplementation
1029// ----------------------------------------------------------------------------------------------------------
1030void GraphicsWindowCocoa::closeImplementation()
1031{
1032    _valid = false;
1033    _realized = false;
1034   
1035    // there's a possibility that the MenubarController is destructed already, so prevent a crash:
1036    MenubarController* mbc = MenubarController::instance();
1037    if (mbc) mbc->detachWindow(this);
1038   
[10208]1039    if (_window) {
1040        [_window close];
1041        [_window release];
1042    }
1043   
1044    if (_view) {
1045        [_view setGraphicsWindowCocoa: NULL];
1046    }
1047   
1048    _window = NULL;
1049    _view = NULL;
1050   
[9879]1051}
1052
1053
1054// ----------------------------------------------------------------------------------------------------------
1055// makeCurrentImplementation
1056// ----------------------------------------------------------------------------------------------------------
1057
1058bool GraphicsWindowCocoa:: makeCurrentImplementation()
1059{
[9895]1060    [_context makeCurrentContext];
1061    return true;
[9879]1062}
1063
1064
1065// ----------------------------------------------------------------------------------------------------------
1066// releaseContextImplementation
1067// ----------------------------------------------------------------------------------------------------------
1068
1069bool GraphicsWindowCocoa::releaseContextImplementation()
1070{
[9895]1071    [NSOpenGLContext clearCurrentContext];
1072    return true;
[9879]1073}
1074
1075
1076// ----------------------------------------------------------------------------------------------------------
1077// swapBuffersImplementation
1078// ----------------------------------------------------------------------------------------------------------
1079
1080void GraphicsWindowCocoa::swapBuffersImplementation()
1081{
[9895]1082    [_context flushBuffer];
[9879]1083}
1084
1085
1086// ----------------------------------------------------------------------------------------------------------
1087// checkEvents
1088// process all pending events
1089// ----------------------------------------------------------------------------------------------------------
1090void GraphicsWindowCocoa::checkEvents()
1091{
[10208]1092    if (!_checkForEvents)
1093        return;
1094   
[9895]1095    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1096   
1097    while(1)
1098    {
1099        /*  NOTE: It may be better to use something like
1100            NSEventTrackingRunLoopMode since we don't necessarily want all
1101            timers/sources/observers to run, only those which would
1102            run while tracking events.  However, it should be noted that
1103            NSEventTrackingRunLoopMode is in the common set of modes
1104            so it may not effectively make much of a difference.
1105         */
[10208]1106        NSEvent *event = [ NSApp
[9879]1107                nextEventMatchingMask:NSAnyEventMask
1108                untilDate:[NSDate distantPast]
1109                inMode:NSDefaultRunLoopMode
1110                dequeue: YES];
1111        if(!event)
1112            break;
[10208]1113        [NSApp sendEvent: event];
[9895]1114    }   
[9879]1115   
1116    if (_closeRequested)
1117        getEventQueue()->closeWindow();
1118       
1119    if (s_quit_requested) {
1120        getEventQueue()->quitApplication();
1121        s_quit_requested = false;
1122    }
1123       
[9895]1124    [pool release];
[9879]1125}
1126
1127
1128
1129// ----------------------------------------------------------------------------------------------------------
1130// setWindowDecorationImplementation
1131//
1132// unfortunately there's no way to change the decoration of a window, so we create an new one
1133// and swap the content
1134// ----------------------------------------------------------------------------------------------------------
1135
1136bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag)
1137{
[10208]1138    if (!_realized || !_ownsWindow) return false;
[9895]1139   
[10208]1140    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1141   
[9879]1142    unsigned int style(NSBorderlessWindowMask);
1143   
1144    if (flag) {
1145        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
1146       
1147        // supportsResize works only with windows with titlebar
1148        if (_traits->supportsResize)
1149            style |= NSResizableWindowMask;
1150    }
[9895]1151    NSRect rect = [_window contentRectForFrameRect: [_window frame] ];
1152    GraphicsWindowCocoaWindow* new_win = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
[9879]1153   
1154    if (new_win) {
1155        [new_win setContentView: [_window contentView]];
1156        setupNSWindow(new_win);
[10242]1157        NSString* title = (_traits.valid()) ? [NSString stringWithUTF8String: _traits->windowName.c_str()] : @"";
1158        [new_win setTitle: title ];
[9879]1159        [_window close];
1160        [_window release];
1161
1162        _window = new_win;
1163        [_window makeKeyAndOrderFront: nil];
1164    }
1165   
[10208]1166    [localPool release];
1167   
[9895]1168    return true;
[9879]1169}
1170
1171
1172// ----------------------------------------------------------------------------------------------------------
1173// grabFocus
1174// ----------------------------------------------------------------------------------------------------------
1175void GraphicsWindowCocoa::grabFocus()
1176{
[10208]1177    if (_ownsWindow)
1178        [_window makeKeyAndOrderFront: nil];
[9879]1179}
1180
1181
1182// ----------------------------------------------------------------------------------------------------------
1183// grabFocusIfPointerInWindow
1184// ----------------------------------------------------------------------------------------------------------
1185void GraphicsWindowCocoa::grabFocusIfPointerInWindow()
1186{
[9895]1187    osg::notify(osg::INFO) << "GraphicsWindowCocoa :: grabFocusIfPointerInWindow not implemented yet " << std::endl;
[9879]1188}
1189
1190
1191// ----------------------------------------------------------------------------------------------------------
1192// resizedImplementation
1193// ----------------------------------------------------------------------------------------------------------
1194
1195void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height)
1196{
[10208]1197    DEBUG_OUT("resized implementation" << x << " " << y << " " << width << " " << height);
[9895]1198    GraphicsContext::resizedImplementation(x, y, width, height);
[10208]1199   
1200    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
[9879]1201   
[10208]1202    if (_context)
1203        [_context update];
[9879]1204    MenubarController::instance()->update();
[9895]1205    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
[10208]1206    [localPool release];
[9879]1207}
1208
1209
1210
1211
1212// ----------------------------------------------------------------------------------------------------------
1213// setWindowRectangleImplementation
1214// ----------------------------------------------------------------------------------------------------------
1215bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height)
1216{
[10208]1217    if (!_ownsWindow)
1218        return false;
1219       
1220    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1221       
[9895]1222    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1223    int screenLeft(0), screenTop(0);
1224    if (wsi) {
1225        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1226    }
1227
1228
1229    NSRect rect = NSMakeRect(x+screenLeft,y+screenTop,width, height);
1230    rect = convertFromQuartzCoordinates(rect);
1231   
1232    [_window setFrame: [NSWindow frameRectForContentRect: rect styleMask: [_window styleMask]] display: YES];
1233    [_context update];
1234    MenubarController::instance()->update();
1235   
[10208]1236    [localPool release];
1237   
[9879]1238    return true;
1239}
1240
1241
1242// ----------------------------------------------------------------------------------------------------------
1243//
1244// ----------------------------------------------------------------------------------------------------------
1245
1246void GraphicsWindowCocoa::adaptResize(int x, int y, int w, int h)
1247{
1248
[9895]1249    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1250    int screenLeft(0), screenTop(0);
1251    if (wsi) {
[9895]1252       
1253        // get the screen containing the window
1254        unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h);
1255       
1256        // update traits
1257        _traits->screenNum = screenNdx;
1258       
1259        // get top left of screen
[9879]1260        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1261    }
[9895]1262   
1263    resized(x-screenLeft,y-screenTop,w,h);
[9879]1264}
1265
1266
1267// ----------------------------------------------------------------------------------------------------------
1268// setWindowName
1269// ----------------------------------------------------------------------------------------------------------
1270
1271void GraphicsWindowCocoa::setWindowName (const std::string & name)
1272{
[10208]1273    if (_traits.valid()) _traits->windowName = name;
1274   
1275    if (!_ownsWindow)
1276        return;
1277       
[9895]1278    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1279   
[10242]1280    NSString* title = [NSString stringWithUTF8String: name.c_str()];
[9895]1281    [_window setTitle: title];
[9879]1282    [pool release];
1283}
1284
1285
1286// ----------------------------------------------------------------------------------------------------------
1287// useCursor
1288// ----------------------------------------------------------------------------------------------------------
1289
1290void GraphicsWindowCocoa::useCursor(bool cursorOn)
1291{
[9895]1292    if (_traits.valid())
[9879]1293        _traits->useCursor = cursorOn;
1294    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
1295    if (wsi == NULL) {
1296        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1297        return;
1298    }
1299   
1300    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1301    CGDisplayErr err = kCGErrorSuccess;
1302    switch (cursorOn)
1303    {
1304        case true:
1305            err = CGDisplayShowCursor(displayId);
1306            break;
1307        case false:
1308            err = CGDisplayHideCursor(displayId);
1309            break;
1310    }
1311    if (err != kCGErrorSuccess) {
1312        osg::notify(osg::WARN) << "GraphicsWindowCocoa::useCursor failed with " << err << std::endl;
1313    }
1314}
1315
1316
1317// ----------------------------------------------------------------------------------------------------------
1318// setCursor
1319// ----------------------------------------------------------------------------------------------------------
1320
1321void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor)
1322{
[10208]1323    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1324   
[9895]1325    switch (mouseCursor)
[9879]1326    {
1327
1328        case NoCursor:
1329            [NSCursor hide];
1330            break;
1331   
1332        case LeftArrowCursor:
1333            [[NSCursor arrowCursor] set];
1334            break;
1335       
1336        case TextCursor:
1337            [[NSCursor IBeamCursor] set];
1338            break;
1339           
1340        case CrosshairCursor:
1341            [[NSCursor crosshairCursor] set];
1342            break;
1343       
1344        default:
1345            osg::notify(osg::INFO) << "GraphicsWindowCocoa::setCursor :: unsupported MouseCursor: " << mouseCursor << std::endl;   
1346    }
[10208]1347   
1348    [localPool release];
[9879]1349}
1350
1351
1352// ----------------------------------------------------------------------------------------------------------
1353// setVSync
1354// ----------------------------------------------------------------------------------------------------------
1355
1356void GraphicsWindowCocoa::setVSync(bool f)
1357{
1358    GLint VBL(f?1:0);
[9895]1359    [_context setValues:&VBL forParameter:NSOpenGLCPSwapInterval];
[9879]1360}
1361
1362
1363// ----------------------------------------------------------------------------------------------------------
1364// d'tor
1365// ----------------------------------------------------------------------------------------------------------
1366
1367GraphicsWindowCocoa::~GraphicsWindowCocoa()
1368{
[10208]1369    close();
[9879]1370}
1371
1372
1373
1374#pragma mark CocoaWindowingSystemInterface
1375
1376// ----------------------------------------------------------------------------------------------------------
1377// CocoaWindowingSystemInterface
1378// ----------------------------------------------------------------------------------------------------------
1379
1380struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface {
[9895]1381   
1382    CocoaWindowingSystemInterface()
[10208]1383    :    DarwinWindowingSystemInterface()
1384   
1385    {       
1386    }
1387   
1388    void initAsStandaloneApplication()
[9895]1389    {
[10208]1390        static bool s_inited = false;
1391        if (s_inited) return;
1392        s_inited = true;
1393       
1394        osg::notify(osg::INFO) << "CocoaWindowingSystemInterface::initAsStandaloneApplication " << std::endl;
1395       
1396        ProcessSerialNumber psn;
1397        if (!GetCurrentProcess(&psn)) {
1398            TransformProcessType(&psn, kProcessTransformToForegroundApplication);
1399            SetFrontProcess(&psn);
1400        }
1401       
1402        NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1403       
1404        if (NSApp == nil) {
1405            [NSApplication sharedApplication];
1406        }
1407       
1408        [NSApp setDelegate: [[CocoaAppDelegate alloc] init] ];
1409       
1410        createApplicationMenus();
1411       
1412        [NSApp finishLaunching];
1413       
1414        [localPool release];
[9895]1415    }
1416   
1417    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1418    {
[10208]1419        if (!traits->pbuffer)
1420        {
1421            GraphicsWindowCocoa::WindowData* windowData = traits->inheritedWindowData ? dynamic_cast<GraphicsWindowCocoa::WindowData*>(traits->inheritedWindowData.get()) : NULL;
1422       
1423            if (!windowData || (windowData && windowData->poseAsStandaloneApp()))
1424            {
1425                initAsStandaloneApplication();
1426            }
1427        }
1428       
[9895]1429        return createGraphicsContextImplementation<PixelBufferCocoa, GraphicsWindowCocoa>(traits);
1430    }
1431   
1432    virtual ~CocoaWindowingSystemInterface()
1433    {
1434    }
1435   
[10208]1436private:
1437    NSString *getApplicationName(void)
1438    {
1439        NSDictionary *dict;
1440        NSString *appName = 0;
[9879]1441
[10208]1442        /* Determine the application name */
1443        dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
1444        if (dict)
1445            appName = [dict objectForKey: @"CFBundleName"];
1446       
1447        if (![appName length])
1448            appName = [[NSProcessInfo processInfo] processName];
1449
1450        return appName;
1451    }
1452   
1453     void createApplicationMenus(void)
1454    {
1455        NSString *appName;
1456        NSString *title;
1457        NSMenu *appleMenu;
1458        NSMenuItem *menuItem;
1459       
1460        /* Create the main menu bar */
1461        [NSApp setMainMenu:[[NSMenu alloc] init]];
1462
1463        /* Create the application menu */
1464        appName = getApplicationName();
1465        appleMenu = [[NSMenu alloc] initWithTitle:@""];
1466       
1467        /* Add menu items */
1468        title = [@"About " stringByAppendingString:appName];
1469        [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
1470
1471        [appleMenu addItem:[NSMenuItem separatorItem]];
1472       
1473        NSMenu* service_menu = [[NSMenu alloc] init];
1474        NSMenuItem* service_menu_item = [[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""];
1475        [service_menu_item setSubmenu: service_menu];
1476        [appleMenu addItem: service_menu_item];
1477        [NSApp setServicesMenu: service_menu];
1478       
1479        [appleMenu addItem:[NSMenuItem separatorItem]];
1480
1481        title = [@"Hide " stringByAppendingString:appName];
1482        [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/"h"];
1483
1484        menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""];
1485        [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
1486
1487        [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
1488
1489        [appleMenu addItem:[NSMenuItem separatorItem]];
1490
1491        title = [@"Quit " stringByAppendingString:appName];
1492        [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/"q"];
1493       
1494        /* Put menu into the menubar */
1495        menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
1496        [menuItem setSubmenu:appleMenu];
1497        [[NSApp mainMenu] addItem:menuItem];
1498        [menuItem release];
1499
1500        /* Tell the application object that this is now the application menu */
1501        [NSApp setAppleMenu:appleMenu];
1502        [appleMenu release];
1503
1504
1505    }
1506
[9879]1507};
1508
1509}
1510
1511#ifdef USE_DARWIN_COCOA_IMPLEMENTATION
1512RegisterWindowingSystemInterfaceProxy<osgViewer::CocoaWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1513#endif
1514
1515// declare C entry point for static compilation.
1516extern "C" void graphicswindow_Cocoa(void)
1517{
1518    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CocoaWindowingSystemInterface());
1519}
Note: See TracBrowser for help on using the browser.