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

Revision 10417, 49.3 kB (checked in by robert, 5 years ago)

From Stephan Huber, fixes to Cocoa support

  • 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
[10417]22//#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl;
[9879]23
[10417]24#define DEBUG_OUT(s) ;
[10208]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;
[10417]46            _keymap[13]     = osgGA::GUIEventAdapter::KEY_Return;
47            _keymap[3]      = osgGA::GUIEventAdapter::KEY_KP_Enter;
[9879]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{
391    NSPoint converted_point = [self getLocalPoint: theEvent];
[10340]392    DEBUG_OUT("Mouse moved" << converted_point.x << "/" << converted_point.y);
[9879]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   
[10340]608    DEBUG_OUT("middleMouseDown ");
609   
[9879]610    NSPoint converted_point = [self getLocalPoint: theEvent];
611   
612    if([theEvent clickCount] == 1)
613    {
614        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 2);
615    }
616    else
617    {
618        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 2);
619    }
620}
621
622- (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number
623{
[10208]624    if (!_win) return;
625   
[10340]626    DEBUG_OUT("extraMouseDown btn: " << button_number);
627   
[9879]628    NSPoint converted_point = [self getLocalPoint: theEvent];
629    if([theEvent clickCount] == 1)
630    {
631        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1);
632    }
633    else
634    {
635        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, button_number+1);
636    }
637}
638
639
640- (void) doMiddleMouseButtonUp:(NSEvent*)theEvent
641{
[10208]642    if (!_win) return;
643   
[9879]644    NSPoint converted_point = [self getLocalPoint: theEvent];
645    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2);
646
647}
648
649- (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number
650{
[10208]651    if (!_win) return;
652   
[9879]653    NSPoint converted_point = [self getLocalPoint: theEvent];
654    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1);
655}
656
657
658
659- (void) scrollWheel:(NSEvent*)theEvent
660{
[10208]661    if (!_win) return;
662   
[9879]663    // Unfortunately, it turns out mouseScroll2D doesn't actually do anything.
664    // The camera manipulators don't seem to implement any code that utilize the scroll values.
665    // This this call does nothing.
666    _win->getEventQueue()->mouseScroll2D([theEvent deltaX], [theEvent deltaY]);
667}
668
669
670
671- (void)keyDown:(NSEvent *)theEvent 
672{
[10208]673    if (!_win) return;
674   
[9879]675    NSString* chars = [theEvent charactersIgnoringModifiers];
[10285]676    if ((chars) && ([chars length] > 0)) {
677        unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask) );
678        // std::cout << "key dn: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
679        _win->getEventQueue()->keyPress( remapCocoaKey(keyCode), [theEvent timestamp]);
680    }
[9879]681}
682
683
684- (void)keyUp:(NSEvent *)theEvent 
685{   
[10208]686    if (!_win) return;
687   
[9879]688    NSString* chars = [theEvent charactersIgnoringModifiers];
[10285]689    if ((chars) && ([chars length] > 0)) {
690        unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask));
691        // std::cout << "key up: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
692        _win->getEventQueue()->keyRelease( remapCocoaKey(keyCode), [theEvent timestamp]);
693    }
[9879]694}
695
696
697- (void)tabletPoint:(NSEvent *)theEvent
698{
[9895]699    //_handleTabletEvents = YES;
700    //[self handleTabletEvents:theEvent];
[9879]701}
702
703-(void)handleTabletEvents:(NSEvent *)theEvent
704{
[10208]705    if (!_win) return;
706   
[9895]707    float pressure = [theEvent pressure];
708    _win->getEventQueue()->penPressure(pressure);
709    NSPoint tilt = [theEvent tilt];
710   
711    _win->getEventQueue()->penOrientation (tilt.x, tilt.y, [theEvent rotation]);
[9879]712}
713
714
715- (void)tabletProximity:(NSEvent *)theEvent
716{
[10208]717    if (!_win) return;
718   
[9895]719    osgGA::GUIEventAdapter::TabletPointerType pt(osgGA::GUIEventAdapter::UNKNOWN);
720    switch ([theEvent pointingDeviceType]) {
721        case NSPenPointingDevice:
722            pt = osgGA::GUIEventAdapter::PEN;
723            break;
724        case NSCursorPointingDevice:
725            pt = osgGA::GUIEventAdapter::PUCK;
726            break;
727        case NSEraserPointingDevice:
728            pt = osgGA::GUIEventAdapter::ERASER;
729            break;
730        default:
731            break;
732    }
733    _win->getEventQueue()->penProximity(pt, [theEvent isEnteringProximity]);
[9879]734}
735
736
737@end
738
739
740#pragma mark GraphicsWindowCocoaDelegate
741
742
743// ----------------------------------------------------------------------------------------------------------
744// the window-delegate, handles moving/resizing of the window etc.
745// ----------------------------------------------------------------------------------------------------------
746
747@interface GraphicsWindowCocoaDelegate : NSObject
748{
749    @private
750        osgViewer::GraphicsWindowCocoa* _win;
751        BOOL                            _inDidMove;
752}
753
754- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win;
755- (void)windowDidMove:(NSNotification *)notification;
756- (void)windowDidResize:(NSNotification *)notification;
757- (BOOL)windowShouldClose:(id)window;
758- (void)updateWindowBounds;
759
760@end
761
762
763@implementation GraphicsWindowCocoaDelegate
764
765- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win
766{
767    _inDidMove = false;
768    _win = win;
769    return [super init];
770}
771
772
773- (void)windowDidMove:(NSNotification *)notification
774{
775    [self updateWindowBounds];
776}
777
778- (void)windowDidResize:(NSNotification *)notification
779{
780    [self updateWindowBounds];
781}
782
783-(void)updateWindowBounds
784{
785    if (_inDidMove) return;
786    _inDidMove = true;
787   
788    GraphicsWindowCocoaWindow* nswin = _win->getWindow();
789    NSRect bounds = [nswin contentRectForFrameRect: [nswin frame] ];
790   
791    // convert to quartz-coordinate-system
792    bounds = convertToQuartzCoordinates(bounds);
793   
794    // std::cout << "windowdidmove: " << bounds.origin.x << " " << bounds.origin.y << " " << bounds.size.width << " " << bounds.size.height << std::endl;
795   
796    _win->adaptResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
797    //_win->getEventQueue()->windowResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height, _win->getEventQueue()->getTime());
798    _win->requestRedraw();
799    _inDidMove = false;
800}
801
802- (BOOL)windowShouldClose:(id)window 
803{
804    return _win->requestClose();
805}
806
807@end
808
809
810#pragma mark CocoaWindowAdapter
811
812
813
814using namespace osgDarwin;
815namespace osgViewer {
816
817
818// ----------------------------------------------------------------------------------------------------------
819// small adapter class to handle the dock/menubar
820// ----------------------------------------------------------------------------------------------------------
821
822class CocoaWindowAdapter : public MenubarController::WindowAdapter {
823public:
824    CocoaWindowAdapter(GraphicsWindowCocoa* win) : MenubarController::WindowAdapter(), _win(win) {}
825   
826    virtual bool valid() { return (_win.valid() && _win->valid()); }
[9895]827   
[9879]828    virtual void getWindowBounds(CGRect& rect)
829    {
830        NSRect nsrect = [_win->getWindow() frame];
831        nsrect = convertToQuartzCoordinates(nsrect);
832       
833        rect.origin.x = nsrect.origin.x;
834        rect.origin.y = nsrect.origin.y;
835        rect.size.width = nsrect.size.width;
836        rect.size.height = nsrect.size.height;
837    }
[9895]838   
[9879]839    virtual osgViewer::GraphicsWindow* getWindow() {return _win.get(); }
840private:
841    osg::observer_ptr<GraphicsWindowCocoa> _win;
842};
843
844#pragma mark GraphicsWindowCocoa
845
846
847
848// ----------------------------------------------------------------------------------------------------------
849// init
850// ----------------------------------------------------------------------------------------------------------
851
852void GraphicsWindowCocoa::init()
853{
854    if (_initialized) return;
855
856    _closeRequested = false;
857    _ownsWindow = false;
858    _context = NULL;
859    _window = NULL;
860    _valid = _initialized = true;
861}
862
863
864// ----------------------------------------------------------------------------------------------------------
865// setupNSWindow
866// sets up the NSWindow, adds delegates, etc
867// ----------------------------------------------------------------------------------------------------------
868
869void GraphicsWindowCocoa::setupNSWindow(NSWindow* win)
870{
871
872    [win setReleasedWhenClosed:NO];
[9895]873    [win setDisplaysWhenScreenProfileChanges:YES];   
[9879]874    GraphicsWindowCocoaDelegate* delegate = [[GraphicsWindowCocoaDelegate alloc] initWith: this];
875    [win setDelegate: delegate ];
876    //[delegate autorelease];
[9895]877       
[9879]878    [win makeKeyAndOrderFront:nil];
879    [win setAcceptsMouseMovedEvents: YES];
880
881}
882
883
884// ----------------------------------------------------------------------------------------------------------
885// realizeImplementation, creates the window + context
886// ----------------------------------------------------------------------------------------------------------
887
888bool GraphicsWindowCocoa::realizeImplementation()
889{
890    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
891   
892    unsigned int style(NSBorderlessWindowMask);
893   
894    if (_traits->windowDecoration) {
895        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
896       
897        // supportsResize works only with windows with titlebar
898        if (_traits->supportsResize)
899            style |= NSResizableWindowMask;
900    }
[9895]901       
[9879]902    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
903    int screenLeft(0), screenTop(0);
904    if (wsi) {
905        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
906    }
907   
[9895]908    NSRect rect = NSMakeRect(_traits->x + screenLeft, _traits->y + screenTop, _traits->width, _traits->height);
[9879]909   
[10208]910    _ownsWindow = true;
[9895]911   
[10208]912    // should we create a NSView only??
913    WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : NULL;
914    if (windowData)
915    {
916        if (windowData->createOnlyView())
917            _ownsWindow = false;
918        _checkForEvents = windowData->checkForEvents();
919       
920    }
[9879]921   
[10208]922
923    osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / ownsWindow: " << _ownsWindow << " checkForEvents: " << _checkForEvents << std::endl;
924
925    if (_ownsWindow)
926    {
927        _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
928       
929        if (!_window) {
930            osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl;
931            return false;
932        }
933
934        rect = convertFromQuartzCoordinates(rect);
935        [_window setFrameOrigin: rect.origin];
936    }
937           
[9895]938    NSOpenGLPixelFormatAttribute attr[32];
[9879]939    int i = 0;
940   
941    attr[i++] = NSOpenGLPFADepthSize;
942    attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->depth);
943
944    if (_traits->doubleBuffer) {
945        attr[i++] = NSOpenGLPFADoubleBuffer;
946    }
947   
948    if (_traits->alpha) {
949        attr[i++] = NSOpenGLPFAAlphaSize;
950        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->alpha);
951    }
952
953    if (_traits->stencil) {
954        attr[i++] = NSOpenGLPFAStencilSize;
955        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->stencil);
956    }
957 
958
959    if (_traits->sampleBuffers) {
960        attr[i++] = NSOpenGLPFASampleBuffers;
961        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->sampleBuffers);
962        attr[i++] = NSOpenGLPFASamples;
963        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->samples);
964    }
965
966   
967    attr[i++] = NSOpenGLPFAAccelerated;
968    attr[i] = static_cast<NSOpenGLPixelFormatAttribute>(0);
969   
970    // create the context
971    NSOpenGLContext* sharedContext = NULL;
972   
973    GraphicsWindowCocoa* graphicsWindowCocoa = dynamic_cast<GraphicsWindowCocoa*>(_traits->sharedContext);
974    if (graphicsWindowCocoa)
975    {
976        sharedContext = graphicsWindowCocoa->getContext();
977    }
978    else
979    {
980        PixelBufferCocoa* pixelbuffer = dynamic_cast<PixelBufferCocoa*>(_traits->sharedContext);
981        if (pixelbuffer) {
982            sharedContext = pixelbuffer->getContext();
983        }
984    }
[9895]985   
986    NSOpenGLPixelFormat* pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ];
[9879]987    _context = [[NSOpenGLContext alloc] initWithFormat: pixelformat shareContext: sharedContext];
988   
989    if (!_context) {
990        osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create context" << std::endl;
991        return false;
992    }
[9895]993    GraphicsWindowCocoaGLView* theView = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ];
[9879]994    [theView setAutoresizingMask:  (NSViewWidthSizable | NSViewHeightSizable) ];
995    [theView setGraphicsWindowCocoa: this];
996    [theView setOpenGLContext:_context];
[10208]997    _view = theView;
998    osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / view: " << theView << std::endl;
999
1000    if (_ownsWindow) {
1001        [_window setContentView: theView];
1002        setupNSWindow(_window);
1003        [theView release];
1004       
1005        MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) );
1006    }
1007    else 
1008    {
1009        windowData->setCreatedNSView(theView);
1010    }
1011
[9879]1012    [pool release];
[9895]1013   
[9879]1014   
1015    useCursor(_traits->useCursor);
1016    setWindowName(_traits->windowName);
1017    setVSync(_traits->vsync);
1018   
1019    MenubarController::instance()->update();
1020   
1021    // Cocoa's origin is bottom/left:
1022    getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
1023   
1024    _valid = _initialized = _realized = true;
1025    return _valid;
1026}
1027
1028
1029
1030
1031// ----------------------------------------------------------------------------------------------------------
1032// closeImplementation
1033// ----------------------------------------------------------------------------------------------------------
1034void GraphicsWindowCocoa::closeImplementation()
1035{
1036    _valid = false;
1037    _realized = false;
1038   
1039    // there's a possibility that the MenubarController is destructed already, so prevent a crash:
1040    MenubarController* mbc = MenubarController::instance();
1041    if (mbc) mbc->detachWindow(this);
1042   
[10208]1043    if (_view) {
1044        [_view setGraphicsWindowCocoa: NULL];
1045    }
[10340]1046       
1047    if (_window) {
1048        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1049       
1050        // we have to close + release the window in the main-thread
1051       
1052        [_window performSelectorOnMainThread: @selector(close) withObject:NULL waitUntilDone: YES];
1053        [_window performSelectorOnMainThread: @selector(release) withObject:NULL waitUntilDone: YES];
1054        [pool release];
1055    }
[10208]1056   
1057    _window = NULL;
[10340]1058    _view = NULL;   
[9879]1059}
1060
1061
1062// ----------------------------------------------------------------------------------------------------------
1063// makeCurrentImplementation
1064// ----------------------------------------------------------------------------------------------------------
1065
1066bool GraphicsWindowCocoa:: makeCurrentImplementation()
1067{
[9895]1068    [_context makeCurrentContext];
1069    return true;
[9879]1070}
1071
1072
1073// ----------------------------------------------------------------------------------------------------------
1074// releaseContextImplementation
1075// ----------------------------------------------------------------------------------------------------------
1076
1077bool GraphicsWindowCocoa::releaseContextImplementation()
1078{
[9895]1079    [NSOpenGLContext clearCurrentContext];
1080    return true;
[9879]1081}
1082
1083
1084// ----------------------------------------------------------------------------------------------------------
1085// swapBuffersImplementation
1086// ----------------------------------------------------------------------------------------------------------
1087
1088void GraphicsWindowCocoa::swapBuffersImplementation()
1089{
[9895]1090    [_context flushBuffer];
[9879]1091}
1092
1093
1094// ----------------------------------------------------------------------------------------------------------
1095// checkEvents
1096// process all pending events
1097// ----------------------------------------------------------------------------------------------------------
1098void GraphicsWindowCocoa::checkEvents()
1099{
[10208]1100    if (!_checkForEvents)
1101        return;
1102   
[9895]1103    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1104   
1105    while(1)
1106    {
1107        /*  NOTE: It may be better to use something like
1108            NSEventTrackingRunLoopMode since we don't necessarily want all
1109            timers/sources/observers to run, only those which would
1110            run while tracking events.  However, it should be noted that
1111            NSEventTrackingRunLoopMode is in the common set of modes
1112            so it may not effectively make much of a difference.
1113         */
[10208]1114        NSEvent *event = [ NSApp
[9879]1115                nextEventMatchingMask:NSAnyEventMask
1116                untilDate:[NSDate distantPast]
1117                inMode:NSDefaultRunLoopMode
1118                dequeue: YES];
1119        if(!event)
1120            break;
[10208]1121        [NSApp sendEvent: event];
[9895]1122    }   
[9879]1123   
1124    if (_closeRequested)
1125        getEventQueue()->closeWindow();
1126       
1127    if (s_quit_requested) {
1128        getEventQueue()->quitApplication();
1129        s_quit_requested = false;
1130    }
1131       
[9895]1132    [pool release];
[9879]1133}
1134
1135
1136
1137// ----------------------------------------------------------------------------------------------------------
1138// setWindowDecorationImplementation
1139//
1140// unfortunately there's no way to change the decoration of a window, so we create an new one
1141// and swap the content
1142// ----------------------------------------------------------------------------------------------------------
1143
1144bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag)
1145{
[10208]1146    if (!_realized || !_ownsWindow) return false;
[9895]1147   
[10208]1148    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1149   
[9879]1150    unsigned int style(NSBorderlessWindowMask);
1151   
1152    if (flag) {
1153        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
1154       
1155        // supportsResize works only with windows with titlebar
1156        if (_traits->supportsResize)
1157            style |= NSResizableWindowMask;
1158    }
[9895]1159    NSRect rect = [_window contentRectForFrameRect: [_window frame] ];
1160    GraphicsWindowCocoaWindow* new_win = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
[9879]1161   
1162    if (new_win) {
1163        [new_win setContentView: [_window contentView]];
1164        setupNSWindow(new_win);
[10242]1165        NSString* title = (_traits.valid()) ? [NSString stringWithUTF8String: _traits->windowName.c_str()] : @"";
1166        [new_win setTitle: title ];
[9879]1167        [_window close];
1168        [_window release];
1169
1170        _window = new_win;
1171        [_window makeKeyAndOrderFront: nil];
1172    }
1173   
[10208]1174    [localPool release];
1175   
[9895]1176    return true;
[9879]1177}
1178
1179
1180// ----------------------------------------------------------------------------------------------------------
1181// grabFocus
1182// ----------------------------------------------------------------------------------------------------------
1183void GraphicsWindowCocoa::grabFocus()
1184{
[10208]1185    if (_ownsWindow)
1186        [_window makeKeyAndOrderFront: nil];
[9879]1187}
1188
1189
1190// ----------------------------------------------------------------------------------------------------------
1191// grabFocusIfPointerInWindow
1192// ----------------------------------------------------------------------------------------------------------
1193void GraphicsWindowCocoa::grabFocusIfPointerInWindow()
1194{
[9895]1195    osg::notify(osg::INFO) << "GraphicsWindowCocoa :: grabFocusIfPointerInWindow not implemented yet " << std::endl;
[9879]1196}
1197
1198
1199// ----------------------------------------------------------------------------------------------------------
1200// resizedImplementation
1201// ----------------------------------------------------------------------------------------------------------
1202
1203void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height)
1204{
[10208]1205    DEBUG_OUT("resized implementation" << x << " " << y << " " << width << " " << height);
[9895]1206    GraphicsContext::resizedImplementation(x, y, width, height);
[10208]1207   
1208    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
[9879]1209   
[10208]1210    if (_context)
1211        [_context update];
[9879]1212    MenubarController::instance()->update();
[9895]1213    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
[10208]1214    [localPool release];
[9879]1215}
1216
1217
1218
1219
1220// ----------------------------------------------------------------------------------------------------------
1221// setWindowRectangleImplementation
1222// ----------------------------------------------------------------------------------------------------------
1223bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height)
1224{
[10208]1225    if (!_ownsWindow)
1226        return false;
1227       
1228    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1229       
[9895]1230    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1231    int screenLeft(0), screenTop(0);
1232    if (wsi) {
1233        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1234    }
1235
1236
1237    NSRect rect = NSMakeRect(x+screenLeft,y+screenTop,width, height);
1238    rect = convertFromQuartzCoordinates(rect);
1239   
1240    [_window setFrame: [NSWindow frameRectForContentRect: rect styleMask: [_window styleMask]] display: YES];
1241    [_context update];
1242    MenubarController::instance()->update();
1243   
[10208]1244    [localPool release];
1245   
[9879]1246    return true;
1247}
1248
1249
1250// ----------------------------------------------------------------------------------------------------------
1251//
1252// ----------------------------------------------------------------------------------------------------------
1253
1254void GraphicsWindowCocoa::adaptResize(int x, int y, int w, int h)
1255{
1256
[9895]1257    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1258    int screenLeft(0), screenTop(0);
1259    if (wsi) {
[9895]1260       
1261        // get the screen containing the window
1262        unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h);
1263       
1264        // update traits
1265        _traits->screenNum = screenNdx;
1266       
1267        // get top left of screen
[9879]1268        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1269    }
[9895]1270   
1271    resized(x-screenLeft,y-screenTop,w,h);
[9879]1272}
1273
1274
1275// ----------------------------------------------------------------------------------------------------------
1276// setWindowName
1277// ----------------------------------------------------------------------------------------------------------
1278
1279void GraphicsWindowCocoa::setWindowName (const std::string & name)
1280{
[10208]1281    if (_traits.valid()) _traits->windowName = name;
1282   
1283    if (!_ownsWindow)
1284        return;
1285       
[9895]1286    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1287   
[10242]1288    NSString* title = [NSString stringWithUTF8String: name.c_str()];
[9895]1289    [_window setTitle: title];
[9879]1290    [pool release];
1291}
1292
1293
1294// ----------------------------------------------------------------------------------------------------------
1295// useCursor
1296// ----------------------------------------------------------------------------------------------------------
1297
1298void GraphicsWindowCocoa::useCursor(bool cursorOn)
1299{
[9895]1300    if (_traits.valid())
[9879]1301        _traits->useCursor = cursorOn;
1302    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
1303    if (wsi == NULL) {
1304        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1305        return;
1306    }
1307   
1308    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1309    CGDisplayErr err = kCGErrorSuccess;
1310    switch (cursorOn)
1311    {
1312        case true:
1313            err = CGDisplayShowCursor(displayId);
1314            break;
1315        case false:
1316            err = CGDisplayHideCursor(displayId);
1317            break;
1318    }
1319    if (err != kCGErrorSuccess) {
1320        osg::notify(osg::WARN) << "GraphicsWindowCocoa::useCursor failed with " << err << std::endl;
1321    }
1322}
1323
1324
1325// ----------------------------------------------------------------------------------------------------------
1326// setCursor
1327// ----------------------------------------------------------------------------------------------------------
1328
1329void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor)
1330{
[10208]1331    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1332   
[9895]1333    switch (mouseCursor)
[9879]1334    {
1335
1336        case NoCursor:
1337            [NSCursor hide];
1338            break;
1339   
1340        case LeftArrowCursor:
1341            [[NSCursor arrowCursor] set];
1342            break;
1343       
1344        case TextCursor:
1345            [[NSCursor IBeamCursor] set];
1346            break;
1347           
1348        case CrosshairCursor:
1349            [[NSCursor crosshairCursor] set];
1350            break;
1351       
1352        default:
1353            osg::notify(osg::INFO) << "GraphicsWindowCocoa::setCursor :: unsupported MouseCursor: " << mouseCursor << std::endl;   
1354    }
[10208]1355   
1356    [localPool release];
[9879]1357}
1358
1359
1360// ----------------------------------------------------------------------------------------------------------
1361// setVSync
1362// ----------------------------------------------------------------------------------------------------------
1363
1364void GraphicsWindowCocoa::setVSync(bool f)
1365{
1366    GLint VBL(f?1:0);
[9895]1367    [_context setValues:&VBL forParameter:NSOpenGLCPSwapInterval];
[9879]1368}
1369
1370
1371// ----------------------------------------------------------------------------------------------------------
1372// d'tor
1373// ----------------------------------------------------------------------------------------------------------
1374
1375GraphicsWindowCocoa::~GraphicsWindowCocoa()
1376{
[10208]1377    close();
[9879]1378}
1379
1380
1381
1382#pragma mark CocoaWindowingSystemInterface
1383
1384// ----------------------------------------------------------------------------------------------------------
1385// CocoaWindowingSystemInterface
1386// ----------------------------------------------------------------------------------------------------------
1387
1388struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface {
[9895]1389   
1390    CocoaWindowingSystemInterface()
[10208]1391    :    DarwinWindowingSystemInterface()
1392   
1393    {       
1394    }
1395   
1396    void initAsStandaloneApplication()
[9895]1397    {
[10208]1398        static bool s_inited = false;
1399        if (s_inited) return;
1400        s_inited = true;
1401       
1402        osg::notify(osg::INFO) << "CocoaWindowingSystemInterface::initAsStandaloneApplication " << std::endl;
1403       
1404        ProcessSerialNumber psn;
1405        if (!GetCurrentProcess(&psn)) {
1406            TransformProcessType(&psn, kProcessTransformToForegroundApplication);
1407            SetFrontProcess(&psn);
1408        }
1409       
1410        NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1411       
1412        if (NSApp == nil) {
1413            [NSApplication sharedApplication];
1414        }
1415       
1416        [NSApp setDelegate: [[CocoaAppDelegate alloc] init] ];
1417       
1418        createApplicationMenus();
1419       
1420        [NSApp finishLaunching];
1421       
1422        [localPool release];
[9895]1423    }
1424   
1425    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1426    {
[10208]1427        if (!traits->pbuffer)
1428        {
1429            GraphicsWindowCocoa::WindowData* windowData = traits->inheritedWindowData ? dynamic_cast<GraphicsWindowCocoa::WindowData*>(traits->inheritedWindowData.get()) : NULL;
1430       
1431            if (!windowData || (windowData && windowData->poseAsStandaloneApp()))
1432            {
1433                initAsStandaloneApplication();
1434            }
1435        }
1436       
[9895]1437        return createGraphicsContextImplementation<PixelBufferCocoa, GraphicsWindowCocoa>(traits);
1438    }
1439   
1440    virtual ~CocoaWindowingSystemInterface()
1441    {
1442    }
1443   
[10208]1444private:
1445    NSString *getApplicationName(void)
1446    {
1447        NSDictionary *dict;
1448        NSString *appName = 0;
[9879]1449
[10208]1450        /* Determine the application name */
1451        dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
1452        if (dict)
1453            appName = [dict objectForKey: @"CFBundleName"];
1454       
1455        if (![appName length])
1456            appName = [[NSProcessInfo processInfo] processName];
1457
1458        return appName;
1459    }
1460   
1461     void createApplicationMenus(void)
1462    {
1463        NSString *appName;
1464        NSString *title;
1465        NSMenu *appleMenu;
1466        NSMenuItem *menuItem;
1467       
1468        /* Create the main menu bar */
1469        [NSApp setMainMenu:[[NSMenu alloc] init]];
1470
1471        /* Create the application menu */
1472        appName = getApplicationName();
1473        appleMenu = [[NSMenu alloc] initWithTitle:@""];
1474       
1475        /* Add menu items */
1476        title = [@"About " stringByAppendingString:appName];
1477        [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
1478
1479        [appleMenu addItem:[NSMenuItem separatorItem]];
1480       
1481        NSMenu* service_menu = [[NSMenu alloc] init];
1482        NSMenuItem* service_menu_item = [[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""];
1483        [service_menu_item setSubmenu: service_menu];
1484        [appleMenu addItem: service_menu_item];
1485        [NSApp setServicesMenu: service_menu];
1486       
1487        [appleMenu addItem:[NSMenuItem separatorItem]];
1488
1489        title = [@"Hide " stringByAppendingString:appName];
1490        [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/"h"];
1491
1492        menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""];
1493        [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
1494
1495        [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
1496
1497        [appleMenu addItem:[NSMenuItem separatorItem]];
1498
1499        title = [@"Quit " stringByAppendingString:appName];
1500        [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/"q"];
1501       
1502        /* Put menu into the menubar */
1503        menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
1504        [menuItem setSubmenu:appleMenu];
1505        [[NSApp mainMenu] addItem:menuItem];
1506        [menuItem release];
1507
1508        /* Tell the application object that this is now the application menu */
1509        [NSApp setAppleMenu:appleMenu];
1510        [appleMenu release];
1511
1512
1513    }
1514
[9879]1515};
1516
1517}
1518
1519#ifdef USE_DARWIN_COCOA_IMPLEMENTATION
1520RegisterWindowingSystemInterfaceProxy<osgViewer::CocoaWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1521#endif
1522
1523// declare C entry point for static compilation.
1524extern "C" void graphicswindow_Cocoa(void)
1525{
1526    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CocoaWindowingSystemInterface());
1527}
Note: See TracBrowser for help on using the browser.