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

Revision 10208, 48.7 kB (checked in by robert, 6 years ago)

From Stephan Huber, "attached you'll find some bugfixes and enhancements for the Cocoa
implementation of GraoicsWindowCocoa?:

Enhancements/Bugfixes:

+ now it's possible to integrate osgViewer better into existing
cocoa-applications:
* create one or more NSOpenGLView(s) and add these to your window(s)
* create one or more NSWindows
* disable the integrated event-polling of osgViewer, and let the work be
done by Cocoa / NSApplicationRun. You'll have to run the osgViewer's
runloop in a separate thread

+ missing menu-event-handling implemented

+ added NSAutoReleasePools where necessary, this fixes some memory-leaks
+ fixed some crashes and thread-issues"

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