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

Revision 9831, 32.3 kB (checked in by shuber, 5 years ago)

* initial development of osgViewerCocoa
* initial import of imageio-plugin
* disabled quicktime-plugin for 64bit
* disabled GraphicsWindowCarbon? for 664bit

  • 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/** remaps a native os x keycode to a GUIEventAdapter-keycode */
134static unsigned int remapCocoaKey(unsigned int key, bool pressedOnKeypad = false)
135{
136    static CocoaKeyboardMap s_CocoaKeyboardMap;
137    return s_CocoaKeyboardMap.remapKey(key, pressedOnKeypad);
138}
139
140
141// ----------------------------------------------------------------------------------------------------------
142// the app-delegate, handling quit-requests
143// ----------------------------------------------------------------------------------------------------------
144
145@interface CocoaAppDelegate : NSObject 
146{
147}
148
149- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
150@end
151
152@implementation CocoaAppDelegate
153- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
154{
155    s_quit_requested = true;
156    std::cout << "quit requested " << std::endl;
157    return NSTerminateNow;
158}
159
160@end
161
162
163
164// ----------------------------------------------------------------------------------------------------------
165// GraphicsWindowCocoaWindow
166// ----------------------------------------------------------------------------------------------------------
167
168@interface GraphicsWindowCocoaWindow : NSWindow
169{
170}
171
172- (BOOL) canBecomeKeyWindow;
173- (BOOL) canBecomeMainWindow;
174
175@end
176
177@implementation GraphicsWindowCocoaWindow
178
179
180- (BOOL) canBecomeKeyWindow
181{
182    return YES;
183}
184
185- (BOOL) canBecomeMainWindow
186{
187    return YES;
188}
189
190@end
191
192// ----------------------------------------------------------------------------------------------------------
193// GraphicsWindowCocoaGLView
194// ----------------------------------------------------------------------------------------------------------
195
196
197@interface GraphicsWindowCocoaGLView : NSOpenGLView
198{
199    @private
200        osgViewer::GraphicsWindowCocoa* _win;
201        BOOL _isUsingCtrlClick, _isUsingOptionClick;
202        unsigned int _cachedModifierFlags;
203       
204}
205- (void)setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win;
206
207- (void)keyDown:(NSEvent *)theEvent;
208- (void)keyUp:(NSEvent *)theEvent;
209
210- (void) mouseMoved:(NSEvent*)the_event;
211- (void) mouseDown:(NSEvent*)the_event;
212- (void) mouseDragged:(NSEvent*)the_event;
213- (void) mouseUp:(NSEvent*)the_event;
214- (void) rightMouseDown:(NSEvent*)the_event;
215- (void) rightMouseDragged:(NSEvent*)the_event;
216- (void) rightMouseUp:(NSEvent*)the_event;
217- (void) otherMouseDown:(NSEvent*)the_event;
218- (void) otherMouseDragged:(NSEvent*)the_event;
219- (void) otherMouseUp:(NSEvent*)the_event;
220
221- (NSPoint) getLocalPoint: (NSEvent*)the_event;
222- (void) handleModifiers: (NSEvent*)the_event;
223- (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click;
224- (BOOL) isUsingCtrlClick;
225- (void) setIsUsingOptionClick:(BOOL)is_using_option_click;
226- (BOOL) isUsingOptionClick;
227
228- (void) doLeftMouseButtonDown:(NSEvent*)the_event;
229- (void) doLeftMouseButtonUp:(NSEvent*)the_event;
230- (void) doRightMouseButtonDown:(NSEvent*)the_event;
231- (void) doRightMouseButtonUp:(NSEvent*)the_event;
232- (void) doMiddleMouseButtonDown:(NSEvent*)the_event;
233- (void) doExtraMouseButtonDown:(NSEvent*)the_event buttonNumber:(int)button_number;
234- (void) doMiddleMouseButtonUp:(NSEvent*)the_event;
235- (void) doExtraMouseButtonUp:(NSEvent*)the_event buttonNumber:(int)button_number;
236- (void) scrollWheel:(NSEvent*)the_event;
237
238- (BOOL)acceptsFirstResponder;
239- (BOOL)becomeFirstResponder;
240- (BOOL)resignFirstResponder;
241
242@end
243
244@implementation GraphicsWindowCocoaGLView 
245
246
247-(void) setGraphicsWindowCocoa: (osgViewer::GraphicsWindowCocoa*) win
248{
249    _win = win;
250}
251
252- (BOOL)acceptsFirstResponder
253{
254  return YES;
255}
256
257- (BOOL)becomeFirstResponder
258{
259  return YES;
260}
261
262- (BOOL)resignFirstResponder
263{
264  return YES;
265}
266
267
268- (NSPoint) getLocalPoint: (NSEvent*)the_event
269{
270    return  [self convertPoint:[the_event locationInWindow] fromView:nil];
271}
272
273
274- (void) handleModifiers: (NSEvent*)the_event
275{
276    unsigned int flags = [the_event modifierFlags];
277   
278    if (flags == _cachedModifierFlags)
279        return;
280   
281    const unsigned int masks[] = {
282        NSShiftKeyMask,
283        NSControlKeyMask,
284        NSAlternateKeyMask,
285        NSCommandKeyMask,
286        NSAlphaShiftKeyMask
287    };
288   
289    const unsigned int keys[] = {
290        osgGA::GUIEventAdapter::KEY_Shift_L,
291        osgGA::GUIEventAdapter::KEY_Control_L,
292        osgGA::GUIEventAdapter::KEY_Alt_L,
293        osgGA::GUIEventAdapter::KEY_Super_L,
294        osgGA::GUIEventAdapter::KEY_Caps_Lock
295    };
296   
297    for(unsigned int i = 0; i < 5; ++i) {
298       
299        if ((flags & masks[i]) && !(_cachedModifierFlags & masks[i]))
300        {
301            _win->getEventQueue()->keyPress(keys[i]);
302        }
303       
304        if (!(flags & masks[i]) && (_cachedModifierFlags & masks[i]))
305        {
306            _win->getEventQueue()->keyRelease(keys[i]);
307        }
308    }
309   
310    _cachedModifierFlags = flags;
311   
312}
313
314- (void) mouseMoved:(NSEvent*)the_event 
315{
316    [self handleModifiers: the_event];
317    NSPoint converted_point = [self getLocalPoint: the_event];
318    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
319}
320
321
322
323- (void) mouseDown:(NSEvent*)the_event
324{
325    [self handleModifiers: the_event];
326    // Because many Mac users have only a 1-button mouse, we should provide ways
327    // to access the button 2 and 3 actions of osgViewer.
328    // I will use the Ctrl modifer to represent right-clicking
329    // and Option modifier to represent middle clicking.
330    if([the_event modifierFlags] & NSControlKeyMask)
331    {
332        [self setIsUsingCtrlClick:YES];
333        [self doRightMouseButtonDown:the_event];
334    }
335    else if([the_event modifierFlags] & NSAlternateKeyMask)
336    {
337        [self setIsUsingOptionClick:YES];
338        [self doMiddleMouseButtonDown:the_event];
339    }
340    else
341    {
342        [self doLeftMouseButtonDown:the_event];
343    }
344}
345
346
347- (void) mouseDragged:(NSEvent*)the_event
348{
349    [self handleModifiers: the_event];
350    NSPoint converted_point = [self getLocalPoint: the_event];   
351    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
352}
353
354
355- (void) mouseUp:(NSEvent*)the_event
356{
357    [self handleModifiers: the_event];
358   
359    // Because many Mac users have only a 1-button mouse, we should provide ways
360    // to access the button 2 and 3 actions of osgViewer.
361    // I will use the Ctrl modifer to represent right-clicking
362    // and Option modifier to represent middle clicking.
363    if([self isUsingCtrlClick] == YES)
364    {
365        [self setIsUsingCtrlClick:NO];
366        [self doRightMouseButtonUp:the_event];
367    }
368    else if([self isUsingOptionClick] == YES)
369    {
370        [self setIsUsingOptionClick:NO];
371        [self doMiddleMouseButtonUp:the_event];
372    }
373    else
374    {
375        [self doLeftMouseButtonUp:the_event];
376    }
377}
378
379- (void) rightMouseDown:(NSEvent*)the_event
380{
381    [self handleModifiers: the_event];
382    [self doRightMouseButtonDown:the_event];
383}
384
385- (void) rightMouseDragged:(NSEvent*)the_event
386{
387    [self handleModifiers: the_event];
388   
389    NSPoint converted_point = [self getLocalPoint: the_event];
390    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
391   
392}
393
394- (void) rightMouseUp:(NSEvent*)the_event
395{
396    [self handleModifiers: the_event];
397    [self doRightMouseButtonUp:the_event];
398}
399
400// "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc).
401- (void) otherMouseDown:(NSEvent*)the_event
402{
403    [self handleModifiers: the_event];
404    // Button 0 is left
405    // Button 1 is right
406    // Button 2 is middle
407    // Button 3 keeps going
408    // osgViewer expects 1 for left, 3 for right, 2 for middle
409    // osgViewer has a reversed number mapping for right and middle compared to Cocoa
410    if([the_event buttonNumber] == 2)
411    {
412        [self doMiddleMouseButtonDown:the_event];
413    }
414    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer
415    {
416        [self doExtraMouseButtonDown:the_event buttonNumber:[the_event buttonNumber]];
417    }
418}
419
420- (void) otherMouseDragged:(NSEvent*)the_event
421{
422    [self handleModifiers: the_event];
423    NSPoint converted_point = [self getLocalPoint: the_event];   
424    _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
425   
426}
427
428// "otherMouse" seems to capture middle button and any other buttons beyond (4th, etc).
429- (void) otherMouseUp:(NSEvent*)the_event
430{
431    [self handleModifiers: the_event];
432   
433    // Button 0 is left
434    // Button 1 is right
435    // Button 2 is middle
436    // Button 3 keeps going
437    // osgViewer expects 1 for left, 3 for right, 2 for middle
438    // osgViewer has a reversed number mapping for right and middle compared to Cocoa
439    if([the_event buttonNumber] == 2)
440    {
441        [self doMiddleMouseButtonUp:the_event];
442    }
443    else // buttonNumber should be 3,4,5,etc; must map to 4,5,6,etc in osgViewer
444    {
445        // I don't think osgViewer does anything for these additional buttons,
446        // but just in case, pass them along. But as a Cocoa programmer, you might
447        // think about things you can do natively here instead of passing the buck.
448        [self doExtraMouseButtonUp:the_event buttonNumber:[the_event buttonNumber]];
449    }
450}
451
452- (void) setIsUsingCtrlClick:(BOOL)is_using_ctrl_click
453{
454    _isUsingCtrlClick = is_using_ctrl_click;
455}
456
457- (BOOL) isUsingCtrlClick
458{
459    return _isUsingCtrlClick;
460}
461
462- (void) setIsUsingOptionClick:(BOOL)is_using_option_click
463{
464    _isUsingOptionClick = is_using_option_click;
465}
466
467- (BOOL) isUsingOptionClick
468{
469    return _isUsingOptionClick;
470}
471
472
473- (void) doLeftMouseButtonDown:(NSEvent*)the_event
474{
475    NSPoint converted_point = [self getLocalPoint: the_event];
476   
477    if([the_event clickCount] == 1)
478    {
479        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 1);
480    }
481    else
482    {
483        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 1);
484    }
485}
486
487- (void) doLeftMouseButtonUp:(NSEvent*)the_event
488{
489    NSPoint converted_point = [self getLocalPoint: the_event];
490   
491    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 1);
492
493}
494
495- (void) doRightMouseButtonDown:(NSEvent*)the_event
496{
497    NSPoint converted_point = [self getLocalPoint: the_event];
498    if([the_event clickCount] == 1)
499    {
500        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 3);
501    }
502    else
503    {
504        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 3);
505    }
506
507}
508
509
510- (void) doRightMouseButtonUp:(NSEvent*)the_event
511{
512    NSPoint converted_point = [self getLocalPoint: the_event];   
513    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 3);
514}
515
516- (void) doMiddleMouseButtonDown:(NSEvent*)the_event
517{
518    NSPoint converted_point = [self getLocalPoint: the_event];
519   
520    if([the_event clickCount] == 1)
521    {
522        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, 2);
523    }
524    else
525    {
526        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, 2);
527    }
528}
529
530- (void) doExtraMouseButtonDown:(NSEvent*)the_event buttonNumber:(int)button_number
531{
532    NSPoint converted_point = [self getLocalPoint: the_event];
533    if([the_event clickCount] == 1)
534    {
535        _win->getEventQueue()->mouseButtonPress(converted_point.x, converted_point.y, button_number+1);
536    }
537    else
538    {
539        _win->getEventQueue()->mouseDoubleButtonPress(converted_point.x, converted_point.y, button_number+1);
540    }
541}
542
543
544- (void) doMiddleMouseButtonUp:(NSEvent*)the_event
545{
546    NSPoint converted_point = [self getLocalPoint: the_event];
547    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2);
548
549}
550
551- (void) doExtraMouseButtonUp:(NSEvent*)the_event buttonNumber:(int)button_number
552{
553    NSPoint converted_point = [self getLocalPoint: the_event];
554    _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1);
555}
556
557
558
559- (void) scrollWheel:(NSEvent*)the_event
560{
561    // Unfortunately, it turns out mouseScroll2D doesn't actually do anything.
562    // The camera manipulators don't seem to implement any code that utilize the scroll values.
563    // This this call does nothing.
564    _win->getEventQueue()->mouseScroll2D([the_event deltaX], [the_event deltaY]);
565}
566
567
568
569- (void)keyDown:(NSEvent *)theEvent 
570{
571    [self handleModifiers: theEvent];
572    NSString* chars = [theEvent charactersIgnoringModifiers];
573    unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask) );
574    // std::cout << "key dn: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
575    _win->getEventQueue()->keyPress( remapCocoaKey(keyCode), [theEvent timestamp]);
576}
577
578
579- (void)keyUp:(NSEvent *)theEvent 
580{   
581    [self handleModifiers: theEvent];
582    NSString* chars = [theEvent charactersIgnoringModifiers];
583    unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask));
584    // std::cout << "key up: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl;   
585    _win->getEventQueue()->keyRelease( remapCocoaKey(keyCode), [theEvent timestamp]);
586}
587
588
589@end
590
591
592#pragma mark GraphicsWindowCocoaDelegate
593
594
595// ----------------------------------------------------------------------------------------------------------
596// the window-delegate, handles moving/resizing of the window etc.
597// ----------------------------------------------------------------------------------------------------------
598
599@interface GraphicsWindowCocoaDelegate : NSObject
600{
601    @private
602        osgViewer::GraphicsWindowCocoa* _win;
603        BOOL                            _inDidMove;
604}
605
606- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win;
607- (void)windowDidMove:(NSNotification *)notification;
608- (BOOL)windowShouldClose:(id)window;
609
610@end
611
612@implementation GraphicsWindowCocoaDelegate
613
614- (id)initWith: (osgViewer::GraphicsWindowCocoa*) win
615{
616    _inDidMove = false;
617    _win = win;
618    return [super init];
619}
620
621- (void)windowDidMove:(NSNotification *)notification
622{
623    if (_inDidMove) return;
624    _inDidMove = true;
625    GraphicsWindowCocoaWindow* nswin = _win->getWindow();
626    NSRect bounds = [nswin contentRectForFrameRect: [nswin frame] ];
627    std::cout << "windowdidmove: " << bounds.origin.x << " " << bounds.origin.y << " " << bounds.size.width << " " << bounds.size.height << std::endl;
628   
629    _win->resized(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
630    _win->getEventQueue()->windowResize(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height, _win->getEventQueue()->getTime());
631    _win->requestRedraw();
632    _inDidMove = false;
633}
634
635- (BOOL)windowShouldClose:(id)window 
636{
637    return _win->requestClose();
638}
639
640@end
641
642
643#pragma mark GraphicsWindowCocoa
644
645
646
647using namespace osgDarwin;
648namespace osgViewer {
649
650
651// ----------------------------------------------------------------------------------------------------------
652// small adapter class to handle the dock/menubar
653// ----------------------------------------------------------------------------------------------------------
654
655class CocoaWindowAdapter : public MenubarController::WindowAdapter {
656public:
657    CocoaWindowAdapter(GraphicsWindowCocoa* win) : MenubarController::WindowAdapter(), _win(win) {}
658   
659    virtual bool valid() { return (_win.valid() && _win->valid()); }
660       
661    virtual void getWindowBounds(CGRect& rect)
662    {
663        NSRect nsrect = [_win->getWindow() frame];
664
665        rect.origin.x = nsrect.origin.x;
666        rect.origin.y = nsrect.origin.y;
667        rect.size.width = nsrect.size.width;
668        rect.size.height = nsrect.size.height;
669    }
670       
671    virtual osgViewer::GraphicsWindow* getWindow() {return _win.get(); }
672private:
673    osg::observer_ptr<GraphicsWindowCocoa> _win;
674};
675
676
677void GraphicsWindowCocoa::init()
678{
679    if (_initialized) return;
680
681    _closeRequested = false;
682    _ownsWindow = false;
683    _context = NULL;
684    _window = NULL;
685    _valid = _initialized = true;
686}
687
688
689
690void GraphicsWindowCocoa::setupNSWindow(NSWindow* win)
691{
692
693    [win setReleasedWhenClosed:NO];
694        [win setDisplaysWhenScreenProfileChanges:YES]; 
695        [win setDelegate: [[GraphicsWindowCocoaDelegate alloc] initWith: this] ];
696       
697    [win makeKeyAndOrderFront:nil];
698    [win setAcceptsMouseMovedEvents: YES];
699
700}
701
702
703
704bool GraphicsWindowCocoa::realizeImplementation()
705{
706    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
707   
708    unsigned int style(NSBorderlessWindowMask);
709   
710    if (_traits->windowDecoration) {
711        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
712       
713        // supportsResize works only with windows with titlebar
714        if (_traits->supportsResize)
715            style |= NSResizableWindowMask;
716    }
717   
718   
719        NSRect rect = NSMakeRect(_traits->x, _traits->y, _traits->width, _traits->height);
720        _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
721       
722    if (!_window) {
723        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation :: could not create window" << std::endl;
724        return false;
725    }
726   
727         
728        NSOpenGLPixelFormatAttribute attr[32];
729    int i = 0;
730   
731    attr[i++] = NSOpenGLPFADepthSize;
732    attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->depth);
733
734    if (_traits->doubleBuffer) {
735        attr[i++] = NSOpenGLPFADoubleBuffer;
736    }
737   
738    if (_traits->alpha) {
739        attr[i++] = NSOpenGLPFAAlphaSize;
740        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->alpha);
741    }
742
743    if (_traits->stencil) {
744        attr[i++] = NSOpenGLPFAStencilSize;
745        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->stencil);
746    }
747 
748
749    if (_traits->sampleBuffers) {
750        attr[i++] = NSOpenGLPFASampleBuffers;
751        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->sampleBuffers);
752        attr[i++] = NSOpenGLPFASamples;
753        attr[i++] = static_cast<NSOpenGLPixelFormatAttribute>(_traits->samples);
754    }
755
756   
757    attr[i++] = NSOpenGLPFAAccelerated;
758    attr[i] = static_cast<NSOpenGLPixelFormatAttribute>(0);
759   
760    // create the context
761    NSOpenGLContext* sharedContext = NULL;
762   
763    GraphicsWindowCocoa* graphicsWindowCocoa = dynamic_cast<GraphicsWindowCocoa*>(_traits->sharedContext);
764    if (graphicsWindowCocoa)
765    {
766        sharedContext = graphicsWindowCocoa->getContext();
767    }
768    else
769    {
770        PixelBufferCocoa* pixelbuffer = dynamic_cast<PixelBufferCocoa*>(_traits->sharedContext);
771        if (pixelbuffer) {
772            sharedContext = pixelbuffer->getContext();
773        }
774    }
775       
776        NSOpenGLPixelFormat* pixelformat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr ];
777    _context = [[NSOpenGLContext alloc] initWithFormat: pixelformat shareContext: sharedContext];
778   
779    if (!_context) {
780        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation :: could not create context" << std::endl;
781        return false;
782    }
783        GraphicsWindowCocoaGLView* theView = [[ GraphicsWindowCocoaGLView alloc ] initWithFrame:[ _window frame ] ];
784    [theView setAutoresizingMask:  (NSViewWidthSizable | NSViewHeightSizable) ];
785    [theView setGraphicsWindowCocoa: this];
786    [theView setOpenGLContext:_context];
787        [_window setContentView: theView];
788       
789    setupNSWindow(_window);
790   
791    [theView release];
792    [pool release];
793       
794    MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) );
795   
796    useCursor(_traits->useCursor);
797    setWindowName(_traits->windowName);
798    setVSync(_traits->vsync);
799   
800    MenubarController::instance()->update();
801   
802    // Cocoa's origin is bottom/left:
803    getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS);
804   
805    _valid = _initialized = _realized = true;
806    return _valid;
807}
808
809
810
811
812
813
814/** Close the graphics context. */
815void GraphicsWindowCocoa::closeImplementation()
816{
817    _valid = false;
818    _realized = false;
819   
820    // there's a possibility that the MenubarController is destructed already, so prevent a crash:
821    MenubarController* mbc = MenubarController::instance();
822    if (mbc) mbc->detachWindow(this);
823   
824        [_window close];
825    [_window release];
826}
827
828/** Make this graphics context current.*/
829bool GraphicsWindowCocoa:: makeCurrentImplementation()
830{
831        [_context makeCurrentContext];
832        return true;
833}
834
835
836/** Release the graphics context.*/
837bool GraphicsWindowCocoa::releaseContextImplementation()
838{
839        [NSOpenGLContext clearCurrentContext];
840        return true;
841}
842
843
844/** Swap the front and back buffers.*/
845void GraphicsWindowCocoa::swapBuffersImplementation()
846{
847        [_context flushBuffer];
848}
849
850
851/** Check to see if any events have been generated.*/
852void GraphicsWindowCocoa::checkEvents()
853{
854        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
855   
856    while(1)
857    {
858        /*  NOTE: It may be better to use something like
859            NSEventTrackingRunLoopMode since we don't necessarily want all
860            timers/sources/observers to run, only those which would
861            run while tracking events.  However, it should be noted that
862            NSEventTrackingRunLoopMode is in the common set of modes
863            so it may not effectively make much of a difference.
864         */
865        NSEvent *event = [ [NSApplication sharedApplication]
866                nextEventMatchingMask:NSAnyEventMask
867                untilDate:[NSDate distantPast]
868                inMode:NSDefaultRunLoopMode
869                dequeue: YES];
870        if(!event)
871            break;
872        [[NSApplication sharedApplication] sendEvent: event];
873    }   
874   
875    if (_closeRequested)
876        getEventQueue()->closeWindow();
877       
878    if (s_quit_requested) {
879        getEventQueue()->quitApplication();
880        s_quit_requested = false;
881    }
882       
883        [pool release];
884}
885
886
887/** Set the window's position and size.*/
888bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height)
889{
890    std::cout << "GraphicsWindowCocoa :: realizeImplementation not implemented yet " << std::endl;
891       
892    MenubarController::instance()->update();
893   
894    return true;
895}
896
897
898/** Set Window decoration.*/
899bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag)
900{
901    if (!_realized) return false;
902       
903    // unfortunately there's no way to change the decoration of a window, so we create an new one and swap the content
904    unsigned int style(NSBorderlessWindowMask);
905   
906    if (flag) {
907        style = NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
908       
909        // supportsResize works only with windows with titlebar
910        if (_traits->supportsResize)
911            style |= NSResizableWindowMask;
912    }
913        NSRect rect = [_window contentRectForFrameRect: [_window frame] ];
914        GraphicsWindowCocoaWindow* new_win = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO];
915   
916    if (new_win) {
917        [new_win setContentView: [_window contentView]];
918        setupNSWindow(new_win);
919        [new_win setTitle: [_window title]];
920        [_window close];
921        [_window release];
922
923        _window = new_win;
924        [_window makeKeyAndOrderFront: nil];
925    }
926
927   
928        return true;
929}
930
931
932/** Get focus.*/
933void GraphicsWindowCocoa::grabFocus()
934{
935        [_window makeKeyAndOrderFront: nil];
936}
937
938
939/** Get focus on if the pointer is in this window.*/
940void GraphicsWindowCocoa::grabFocusIfPointerInWindow()
941{
942        std::cout << "GraphicsWindowCocoa :: grabFocusIfPointerInWindow not implemented yet " << std::endl;
943}
944
945
946void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height)
947{
948        GraphicsContext::resizedImplementation(x, y, width, height);
949   
950    [_window setContentSize: NSMakeSize(width, height)];
951    [_context update];
952    //[_window setFrameTopLeftPoint: NSMakePoint(x,y)];   
953    MenubarController::instance()->update();
954    std::cout << "GraphicsWindowCocoa :: resizedImplementation not implemented yet " << std::endl;
955}
956
957
958void GraphicsWindowCocoa::setWindowName (const std::string & name)
959{
960        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
961   
962    NSString* title = [NSString stringWithCString: name.c_str() encoding: NSUTF8StringEncoding];
963        [_window setTitle: title];
964        [title release];
965    [pool release];
966}
967
968
969void GraphicsWindowCocoa::useCursor(bool cursorOn)
970{
971        if (_traits.valid())
972        _traits->useCursor = cursorOn;
973    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
974    if (wsi == NULL) {
975        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
976        return;
977    }
978   
979    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
980    CGDisplayErr err = kCGErrorSuccess;
981    switch (cursorOn)
982    {
983        case true:
984            err = CGDisplayShowCursor(displayId);
985            break;
986        case false:
987            err = CGDisplayHideCursor(displayId);
988            break;
989    }
990    if (err != kCGErrorSuccess) {
991        osg::notify(osg::WARN) << "GraphicsWindowCocoa::useCursor failed with " << err << std::endl;
992    }
993}
994
995
996void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor)
997{
998        std::cout << "GraphicsWindowCocoa :: setCursor not implemented yet " << std::endl;
999}
1000
1001void GraphicsWindowCocoa::setVSync(bool f)
1002{
1003    GLint VBL(f?1:0);
1004        [_context setValues:&VBL forParameter:NSOpenGLCPSwapInterval];
1005}
1006
1007
1008GraphicsWindowCocoa::~GraphicsWindowCocoa()
1009{
1010}
1011
1012
1013
1014
1015
1016struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface {
1017       
1018        CocoaWindowingSystemInterface()
1019        :       DarwinWindowingSystemInterface()
1020        {
1021                localPool = [[NSAutoreleasePool alloc] init];
1022        [[NSApplication sharedApplication] setDelegate: [[CocoaAppDelegate alloc] init] ];
1023        }
1024       
1025        virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1026        {
1027                return createGraphicsContextImplementation<PixelBufferCocoa, GraphicsWindowCocoa>(traits);
1028        }
1029       
1030        virtual ~CocoaWindowingSystemInterface()
1031        {
1032                [localPool release];
1033        }
1034       
1035        NSAutoreleasePool *localPool;
1036
1037};
1038
1039
1040}
1041
1042#ifdef USE_DARWIN_COCOA_IMPLEMENTATION
1043RegisterWindowingSystemInterfaceProxy<osgViewer::CocoaWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1044#endif
1045
1046// declare C entry point for static compilation.
1047extern "C" void graphicswindow_Cocoa(void)
1048{
1049    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CocoaWindowingSystemInterface());
1050}
Note: See TracBrowser for help on using the browser.