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

Revision 10887, 49.1 kB (checked in by robert, 4 years ago)

From Stephan Huber, "attached you'll find the missing GraphicsHandleCocoa?-implementation."

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