root/OpenSceneGraph/branches/osg-cocoa-dev/src/osgViewer/GraphicsWindowCocoa.mm @ 9836

Revision 9836, 39.5 kB (checked in by shuber, 5 years ago)

* fixed several issues with GraphicsWindowCocoa?, correct window-placement + resizing,
* first cut of PixelBufferCocoa?

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