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

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

From Stephan Huber, "ttached you'll find a small fix for the
GraphicsWindowCocoa?-implementation, which enhances multithreaded
stability, it ensures that modifications to the size of an openglcontext
is done only from one thread.
"

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