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

Revision 11289, 49.1 kB (checked in by robert, 5 years ago)

From Stephan Huber, "attached you'll find a small enhancement for GraphicsWindowCocoa?. My
submision adds a getter for the pixel-format. I need this for some
custom software so I can integrate CoreVideo?-playback with osg.
"

  • 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;
[11289]860    _pixelformat = NULL;
861   
[10456]862    _updateContext = false;
[9879]863    _valid = _initialized = true;
864}
865
866
867// ----------------------------------------------------------------------------------------------------------
868// setupNSWindow
869// sets up the NSWindow, adds delegates, etc
870// ----------------------------------------------------------------------------------------------------------
871
872void GraphicsWindowCocoa::setupNSWindow(NSWindow* win)
873{
874
875    [win setReleasedWhenClosed:NO];
[9895]876    [win setDisplaysWhenScreenProfileChanges:YES];   
[9879]877    GraphicsWindowCocoaDelegate* delegate = [[GraphicsWindowCocoaDelegate alloc] initWith: this];
878    [win setDelegate: delegate ];
879    //[delegate autorelease];
[9895]880       
[9879]881    [win makeKeyAndOrderFront:nil];
882    [win setAcceptsMouseMovedEvents: YES];
883
884}
885
886
887// ----------------------------------------------------------------------------------------------------------
888// realizeImplementation, creates the window + context
889// ----------------------------------------------------------------------------------------------------------
890
891bool GraphicsWindowCocoa::realizeImplementation()
892{
893    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
894   
895    unsigned int style(NSBorderlessWindowMask);
896   
897    if (_traits->windowDecoration) {
898        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
899       
900        // supportsResize works only with windows with titlebar
901        if (_traits->supportsResize)
902            style |= NSResizableWindowMask;
903    }
[9895]904       
[9879]905    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
906    int screenLeft(0), screenTop(0);
907    if (wsi) {
908        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
909    }
910   
[9895]911    NSRect rect = NSMakeRect(_traits->x + screenLeft, _traits->y + screenTop, _traits->width, _traits->height);
[9879]912   
[10208]913    _ownsWindow = true;
[9895]914   
[10208]915    // should we create a NSView only??
916    WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : NULL;
917    if (windowData)
918    {
919        if (windowData->createOnlyView())
920            _ownsWindow = false;
921        _checkForEvents = windowData->checkForEvents();
922       
923    }
[9879]924   
[10208]925
926    osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / ownsWindow: " << _ownsWindow << " checkForEvents: " << _checkForEvents << std::endl;
927
928    if (_ownsWindow)
929    {
930        _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
931       
932        if (!_window) {
933            osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl;
934            return false;
935        }
936
937        rect = convertFromQuartzCoordinates(rect);
938        [_window setFrameOrigin: rect.origin];
939    }
940           
[9895]941    NSOpenGLPixelFormatAttribute attr[32];
[9879]942    int i = 0;
943   
944    attr[i++] = NSOpenGLPFADepthSize;
945    attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->depth);
946
947    if (_traits->doubleBuffer) {
948        attr[i++] = NSOpenGLPFADoubleBuffer;
949    }
950   
951    if (_traits->alpha) {
952        attr[i++] = NSOpenGLPFAAlphaSize;
953        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->alpha);
954    }
955
956    if (_traits->stencil) {
957        attr[i++] = NSOpenGLPFAStencilSize;
958        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->stencil);
959    }
960 
961
962    if (_traits->sampleBuffers) {
963        attr[i++] = NSOpenGLPFASampleBuffers;
964        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->sampleBuffers);
965        attr[i++] = NSOpenGLPFASamples;
966        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->samples);
967    }
968
969   
970    attr[i++] = NSOpenGLPFAAccelerated;
971    attr[i] = static_cast<NSOpenGLPixelFormatAttribute>(0);
972   
973    // create the context
974    NSOpenGLContext* sharedContext = NULL;
975   
[10887]976    GraphicsHandleCocoa* graphicsHandleCocoa = dynamic_cast<GraphicsHandleCocoa*>(_traits->sharedContext);
977    if (graphicsHandleCocoa)
[9879]978    {
[10887]979        sharedContext = graphicsHandleCocoa->getNSOpenGLContext();
[9879]980    }
[9895]981   
[11289]982    _pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ];
983    _context = [[NSOpenGLContext alloc] initWithFormat: _pixelformat shareContext: sharedContext];
[9879]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 (_view) {
1040        [_view setGraphicsWindowCocoa: NULL];
1041    }
[10340]1042       
1043    if (_window) {
1044        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1045       
1046        // we have to close + release the window in the main-thread
1047       
1048        [_window performSelectorOnMainThread: @selector(close) withObject:NULL waitUntilDone: YES];
1049        [_window performSelectorOnMainThread: @selector(release) withObject:NULL waitUntilDone: YES];
1050        [pool release];
1051    }
[10208]1052   
1053    _window = NULL;
[10340]1054    _view = NULL;   
[9879]1055}
1056
1057
1058// ----------------------------------------------------------------------------------------------------------
1059// makeCurrentImplementation
1060// ----------------------------------------------------------------------------------------------------------
1061
1062bool GraphicsWindowCocoa:: makeCurrentImplementation()
1063{
[10456]1064    if (_updateContext)
1065    {
1066        [_context update];
1067        _updateContext = false;
1068    }
1069   
[9895]1070    [_context makeCurrentContext];
1071    return true;
[9879]1072}
1073
1074
1075// ----------------------------------------------------------------------------------------------------------
1076// releaseContextImplementation
1077// ----------------------------------------------------------------------------------------------------------
1078
1079bool GraphicsWindowCocoa::releaseContextImplementation()
1080{
[9895]1081    [NSOpenGLContext clearCurrentContext];
1082    return true;
[9879]1083}
1084
1085
1086// ----------------------------------------------------------------------------------------------------------
1087// swapBuffersImplementation
1088// ----------------------------------------------------------------------------------------------------------
1089
1090void GraphicsWindowCocoa::swapBuffersImplementation()
1091{
[9895]1092    [_context flushBuffer];
[9879]1093}
1094
1095
1096// ----------------------------------------------------------------------------------------------------------
1097// checkEvents
1098// process all pending events
1099// ----------------------------------------------------------------------------------------------------------
1100void GraphicsWindowCocoa::checkEvents()
1101{
[10208]1102    if (!_checkForEvents)
1103        return;
1104   
[9895]1105    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1106   
1107    while(1)
1108    {
1109        /*  NOTE: It may be better to use something like
1110            NSEventTrackingRunLoopMode since we don't necessarily want all
1111            timers/sources/observers to run, only those which would
1112            run while tracking events.  However, it should be noted that
1113            NSEventTrackingRunLoopMode is in the common set of modes
1114            so it may not effectively make much of a difference.
1115         */
[10208]1116        NSEvent *event = [ NSApp
[9879]1117                nextEventMatchingMask:NSAnyEventMask
1118                untilDate:[NSDate distantPast]
1119                inMode:NSDefaultRunLoopMode
1120                dequeue: YES];
1121        if(!event)
1122            break;
[10208]1123        [NSApp sendEvent: event];
[9895]1124    }   
[9879]1125   
1126    if (_closeRequested)
1127        getEventQueue()->closeWindow();
1128       
1129    if (s_quit_requested) {
1130        getEventQueue()->quitApplication();
1131        s_quit_requested = false;
1132    }
1133       
[9895]1134    [pool release];
[9879]1135}
1136
1137
1138
1139// ----------------------------------------------------------------------------------------------------------
1140// setWindowDecorationImplementation
1141//
1142// unfortunately there's no way to change the decoration of a window, so we create an new one
1143// and swap the content
1144// ----------------------------------------------------------------------------------------------------------
1145
1146bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag)
1147{
[10208]1148    if (!_realized || !_ownsWindow) return false;
[9895]1149   
[10208]1150    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1151   
[9879]1152    unsigned int style(NSBorderlessWindowMask);
1153   
1154    if (flag) {
1155        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
1156       
1157        // supportsResize works only with windows with titlebar
1158        if (_traits->supportsResize)
1159            style |= NSResizableWindowMask;
1160    }
[9895]1161    NSRect rect = [_window contentRectForFrameRect: [_window frame] ];
1162    GraphicsWindowCocoaWindow* new_win = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
[9879]1163   
1164    if (new_win) {
1165        [new_win setContentView: [_window contentView]];
1166        setupNSWindow(new_win);
[10242]1167        NSString* title = (_traits.valid()) ? [NSString stringWithUTF8String: _traits->windowName.c_str()] : @"";
1168        [new_win setTitle: title ];
[9879]1169        [_window close];
1170        [_window release];
1171
1172        _window = new_win;
1173        [_window makeKeyAndOrderFront: nil];
1174    }
1175   
[10208]1176    [localPool release];
1177   
[9895]1178    return true;
[9879]1179}
1180
1181
1182// ----------------------------------------------------------------------------------------------------------
1183// grabFocus
1184// ----------------------------------------------------------------------------------------------------------
1185void GraphicsWindowCocoa::grabFocus()
1186{
[10208]1187    if (_ownsWindow)
1188        [_window makeKeyAndOrderFront: nil];
[9879]1189}
1190
1191
1192// ----------------------------------------------------------------------------------------------------------
1193// grabFocusIfPointerInWindow
1194// ----------------------------------------------------------------------------------------------------------
1195void GraphicsWindowCocoa::grabFocusIfPointerInWindow()
1196{
[9895]1197    osg::notify(osg::INFO) << "GraphicsWindowCocoa :: grabFocusIfPointerInWindow not implemented yet " << std::endl;
[9879]1198}
1199
1200
1201// ----------------------------------------------------------------------------------------------------------
1202// resizedImplementation
1203// ----------------------------------------------------------------------------------------------------------
1204
1205void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height)
1206{
[10208]1207    DEBUG_OUT("resized implementation" << x << " " << y << " " << width << " " << height);
[9895]1208    GraphicsContext::resizedImplementation(x, y, width, height);
[10208]1209   
[10456]1210    _updateContext = true;
1211   
[9879]1212    MenubarController::instance()->update();
[9895]1213    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
[9879]1214}
1215
1216
1217
1218
1219// ----------------------------------------------------------------------------------------------------------
1220// setWindowRectangleImplementation
1221// ----------------------------------------------------------------------------------------------------------
1222bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height)
1223{
[10208]1224    if (!_ownsWindow)
1225        return false;
1226       
1227    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1228       
[9895]1229    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1230    int screenLeft(0), screenTop(0);
1231    if (wsi) {
1232        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1233    }
1234
1235
1236    NSRect rect = NSMakeRect(x+screenLeft,y+screenTop,width, height);
1237    rect = convertFromQuartzCoordinates(rect);
1238   
1239    [_window setFrame: [NSWindow frameRectForContentRect: rect styleMask: [_window styleMask]] display: YES];
1240    [_context update];
1241    MenubarController::instance()->update();
1242   
[10208]1243    [localPool release];
1244   
[9879]1245    return true;
1246}
1247
1248
1249// ----------------------------------------------------------------------------------------------------------
1250//
1251// ----------------------------------------------------------------------------------------------------------
1252
1253void GraphicsWindowCocoa::adaptResize(int x, int y, int w, int h)
1254{
1255
[9895]1256    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9879]1257    int screenLeft(0), screenTop(0);
1258    if (wsi) {
[9895]1259       
1260        // get the screen containing the window
1261        unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h);
1262       
1263        // update traits
1264        _traits->screenNum = screenNdx;
1265       
1266        // get top left of screen
[9879]1267        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
1268    }
[9895]1269   
1270    resized(x-screenLeft,y-screenTop,w,h);
[9879]1271}
1272
1273
1274// ----------------------------------------------------------------------------------------------------------
1275// setWindowName
1276// ----------------------------------------------------------------------------------------------------------
1277
1278void GraphicsWindowCocoa::setWindowName (const std::string & name)
1279{
[10208]1280    if (_traits.valid()) _traits->windowName = name;
1281   
1282    if (!_ownsWindow)
1283        return;
1284       
[9895]1285    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[9879]1286   
[10242]1287    NSString* title = [NSString stringWithUTF8String: name.c_str()];
[9895]1288    [_window setTitle: title];
[9879]1289    [pool release];
1290}
1291
1292
1293// ----------------------------------------------------------------------------------------------------------
1294// useCursor
1295// ----------------------------------------------------------------------------------------------------------
1296
1297void GraphicsWindowCocoa::useCursor(bool cursorOn)
1298{
[9895]1299    if (_traits.valid())
[9879]1300        _traits->useCursor = cursorOn;
1301    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
1302    if (wsi == NULL) {
1303        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1304        return;
1305    }
1306   
1307    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1308    CGDisplayErr err = kCGErrorSuccess;
1309    switch (cursorOn)
1310    {
1311        case true:
1312            err = CGDisplayShowCursor(displayId);
1313            break;
1314        case false:
1315            err = CGDisplayHideCursor(displayId);
1316            break;
1317    }
1318    if (err != kCGErrorSuccess) {
1319        osg::notify(osg::WARN) << "GraphicsWindowCocoa::useCursor failed with " << err << std::endl;
1320    }
1321}
1322
1323
1324// ----------------------------------------------------------------------------------------------------------
1325// setCursor
1326// ----------------------------------------------------------------------------------------------------------
1327
1328void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor)
1329{
[10208]1330    NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
1331   
[9895]1332    switch (mouseCursor)
[9879]1333    {
1334
1335        case NoCursor:
1336            [NSCursor hide];
1337            break;
1338   
1339        case LeftArrowCursor:
1340            [[NSCursor arrowCursor] set];
1341            break;
1342       
1343        case TextCursor:
1344            [[NSCursor IBeamCursor] set];
1345            break;
1346           
1347        case CrosshairCursor:
1348            [[NSCursor crosshairCursor] set];
1349            break;
1350       
1351        default:
1352            osg::notify(osg::INFO) << "GraphicsWindowCocoa::setCursor :: unsupported MouseCursor: " << mouseCursor << std::endl;   
1353    }
[10208]1354   
1355    [localPool release];
[9879]1356}
1357
1358
1359// ----------------------------------------------------------------------------------------------------------
1360// setVSync
1361// ----------------------------------------------------------------------------------------------------------
1362
1363void GraphicsWindowCocoa::setVSync(bool f)
1364{
1365    GLint VBL(f?1:0);
[9895]1366    [_context setValues:&VBL forParameter:NSOpenGLCPSwapInterval];
[9879]1367}
1368
1369
1370// ----------------------------------------------------------------------------------------------------------
1371// d'tor
1372// ----------------------------------------------------------------------------------------------------------
1373
1374GraphicsWindowCocoa::~GraphicsWindowCocoa()
1375{
[10208]1376    close();
[9879]1377}
1378
1379
1380
1381#pragma mark CocoaWindowingSystemInterface
1382
1383// ----------------------------------------------------------------------------------------------------------
1384// CocoaWindowingSystemInterface
1385// ----------------------------------------------------------------------------------------------------------
1386
[11207]1387struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface
1388{
1389
1390    CocoaWindowingSystemInterface() : DarwinWindowingSystemInterface()
1391    {
[10208]1392    }
[11207]1393
[10208]1394    void initAsStandaloneApplication()
[9895]1395    {
[11207]1396        _init();
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    {
[11207]1427        _init();
1428
[10208]1429        if (!traits->pbuffer)
1430        {
1431            GraphicsWindowCocoa::WindowData* windowData = traits->inheritedWindowData ? dynamic_cast<GraphicsWindowCocoa::WindowData*>(traits->inheritedWindowData.get()) : NULL;
1432       
1433            if (!windowData || (windowData && windowData->poseAsStandaloneApp()))
1434            {
1435                initAsStandaloneApplication();
1436            }
1437        }
1438       
[9895]1439        return createGraphicsContextImplementation<PixelBufferCocoa, GraphicsWindowCocoa>(traits);
1440    }
1441   
1442    virtual ~CocoaWindowingSystemInterface()
1443    {
1444    }
1445   
[10208]1446private:
1447    NSString *getApplicationName(void)
1448    {
1449        NSDictionary *dict;
1450        NSString *appName = 0;
[9879]1451
[10208]1452        /* Determine the application name */
1453        dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
1454        if (dict)
1455            appName = [dict objectForKey: @"CFBundleName"];
1456       
1457        if (![appName length])
1458            appName = [[NSProcessInfo processInfo] processName];
1459
1460        return appName;
1461    }
1462   
1463     void createApplicationMenus(void)
1464    {
1465        NSString *appName;
1466        NSString *title;
1467        NSMenu *appleMenu;
1468        NSMenuItem *menuItem;
1469       
1470        /* Create the main menu bar */
1471        [NSApp setMainMenu:[[NSMenu alloc] init]];
1472
1473        /* Create the application menu */
1474        appName = getApplicationName();
1475        appleMenu = [[NSMenu alloc] initWithTitle:@""];
1476       
1477        /* Add menu items */
1478        title = [@"About " stringByAppendingString:appName];
1479        [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
1480
1481        [appleMenu addItem:[NSMenuItem separatorItem]];
1482       
1483        NSMenu* service_menu = [[NSMenu alloc] init];
1484        NSMenuItem* service_menu_item = [[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""];
1485        [service_menu_item setSubmenu: service_menu];
1486        [appleMenu addItem: service_menu_item];
1487        [NSApp setServicesMenu: service_menu];
1488       
1489        [appleMenu addItem:[NSMenuItem separatorItem]];
1490
1491        title = [@"Hide " stringByAppendingString:appName];
1492        [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/"h"];
1493
1494        menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""];
1495        [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
1496
1497        [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
1498
1499        [appleMenu addItem:[NSMenuItem separatorItem]];
1500
1501        title = [@"Quit " stringByAppendingString:appName];
1502        [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/"q"];
1503       
1504        /* Put menu into the menubar */
1505        menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
1506        [menuItem setSubmenu:appleMenu];
1507        [[NSApp mainMenu] addItem:menuItem];
1508        [menuItem release];
1509
1510        /* Tell the application object that this is now the application menu */
1511        [NSApp setAppleMenu:appleMenu];
1512        [appleMenu release];
1513
1514
1515    }
1516
[9879]1517};
1518
1519}
1520
1521#ifdef USE_DARWIN_COCOA_IMPLEMENTATION
1522RegisterWindowingSystemInterfaceProxy<osgViewer::CocoaWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1523#endif
1524
1525// declare C entry point for static compilation.
1526extern "C" void graphicswindow_Cocoa(void)
1527{
1528    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CocoaWindowingSystemInterface());
1529}
Note: See TracBrowser for help on using the browser.