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

Revision 9836, 10.7 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 *  DarwinUtils.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 */
9
10#include <osg/Referenced>
11#include <osg/DeleteHandler>
12#include "DarwinUtils.h"
13#include <Cocoa/Cocoa.h>
14
15namespace osgDarwin {
16
17
18static inline CGRect toCGRect(NSRect nsRect)
19{
20        CGRect cgRect;
21
22        cgRect.origin.x = nsRect.origin.x;
23        cgRect.origin.y = nsRect.origin.y;
24        cgRect.size.width = nsRect.size.width;
25        cgRect.size.height = nsRect.size.height;
26
27        return cgRect;
28}
29
30
31MenubarController::MenubarController()
32:       osg::Referenced(),
33    _list(),
34    _menubarShown(false),
35    _mutex()
36{
37        // the following code will query the system for the available rect on the main-display (typically the displaying showing the menubar + the dock
38
39        NSRect rect = [[[NSScreen screens] objectAtIndex: 0] visibleFrame];
40        _availRect = toCGRect(rect);
41       
42        // now we need the rect of the main-display including the menubar and the dock
43        _mainScreenBounds = CGDisplayBounds( CGMainDisplayID() );
44
45
46        // NSRect 0/0 is bottom/left, _mainScreenBounds 0/0 is top/left
47        _availRect.origin.y = _mainScreenBounds.size.height - _availRect.size.height - _availRect.origin.y;
48       
49               
50        // hide the menubar initially
51        SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
52}
53
54
55
56
57MenubarController* MenubarController::instance()
58{
59    static osg::ref_ptr<MenubarController> s_menubar_controller = new MenubarController();
60    return s_menubar_controller.get();
61}
62
63
64void MenubarController::attachWindow(WindowAdapter* win)
65{
66    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
67    _list.push_back(win);
68    update();
69}
70
71
72void MenubarController::detachWindow(osgViewer::GraphicsWindow* win)
73{
74    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
75    for(WindowList::iterator i = _list.begin(); i != _list.end(); ) {
76        if ((*i)->getWindow() == win)
77            i = _list.erase(i);
78        else 
79            ++i;
80    }
81    update();
82}
83
84// iterate through all open windows and check, if they intersect the area occupied by the menubar/dock, and if so, hide the menubar/dock
85
86void MenubarController::update()
87{
88    OSErr error(noErr);
89    unsigned int windowsCoveringMenubarArea = 0;   
90    unsigned int windowsIntersectingMainScreen = 0;
91    for(WindowList::iterator i = _list.begin(); i != _list.end(); ) {
92                WindowAdapter* wi = (*i).get();
93        if (wi->valid()) {
94            CGRect windowBounds;
95                        wi->getWindowBounds(windowBounds);
96                       
97                        if (CGRectIntersectsRect(_mainScreenBounds, windowBounds))
98            {
99                ++windowsIntersectingMainScreen;
100                // osg::notify(osg::ALWAYS) << "testing rect " << windowBounds.origin.x << "/" << windowBounds.origin.y << " " << windowBounds.size.width << "x" << windowBounds.size.height << std::endl;
101                                // osg::notify(osg::ALWAYS) << "against      " << _availRect.origin.x << "/" << _availRect.origin.y << " " << _availRect.size.width << "x" << _availRect.size.height << std::endl;
102                // the window intersects the main-screen, does it intersect with the menubar/dock?
103                if (((_availRect.origin.y > _mainScreenBounds.origin.y) && (_availRect.origin.y > windowBounds.origin.y)) ||
104                    ((_availRect.origin.x > _mainScreenBounds.origin.x) && (_availRect.origin.x > windowBounds.origin.x)) ||
105                    ((_availRect.size.width < _mainScreenBounds.size.width) && (_availRect.origin.x + _availRect.size.width < windowBounds.origin.x + windowBounds.size.width)) ||
106                    ((_availRect.size.height < _mainScreenBounds.size.height) && (_availRect.origin.y + _availRect.size.height < windowBounds.origin.y + windowBounds.size.height) ))
107                {
108                    ++windowsCoveringMenubarArea;
109                }
110            }
111           
112            ++i;
113        }
114        else
115            i= _list.erase(i);
116    }
117   
118    // see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar
119       
120    if (windowsCoveringMenubarArea && _menubarShown)
121        error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
122   
123    if (!windowsCoveringMenubarArea && !_menubarShown)
124        error = SetSystemUIMode(kUIModeNormal, 0);
125        _menubarShown = !windowsCoveringMenubarArea;
126   
127    // osg::notify(osg::DEBUG_INFO) << "MenubarController:: " << windowsCoveringMenubarArea << " windows covering the menubar/dock area, " << windowsIntersectingMainScreen << " intersecting mainscreen" << std::endl;
128}
129
130
131
132/** Helper method to get a double value out of a CFDictionary */
133static double getDictDouble (CFDictionaryRef refDict, CFStringRef key)
134{
135        double value;
136        CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key);
137        if (!number_value) // if can't get a number for the dictionary
138                return -1;  // fail
139        if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &value)) // or if cant convert it
140                return -1; // fail
141        return value; // otherwise return the long value
142}
143
144/** Helper method to get a long value out of a CFDictionary */
145static long getDictLong(CFDictionaryRef refDict, CFStringRef key)        // const void* key?
146{
147        long value = 0;
148        CFNumberRef number_value = (CFNumberRef)CFDictionaryGetValue(refDict, key);
149        if (!number_value) // if can't get a number for the dictionary
150                return -1;  // fail
151        if (!CFNumberGetValue(number_value, kCFNumberLongType, &value)) // or if cant convert it
152                return -1; // fail
153        return value;
154}
155
156
157
158/** ctor, get a list of all attached displays */
159DarwinWindowingSystemInterface::DarwinWindowingSystemInterface() :
160        _displayCount(0),
161        _displayIds(NULL)
162{
163        ProcessSerialNumber sn = { 0, kCurrentProcess };
164        TransformProcessType(&sn,kProcessTransformToForegroundApplication);
165        SetFrontProcess(&sn);
166       
167        if( CGGetActiveDisplayList( 0, NULL, &_displayCount ) != CGDisplayNoErr )
168                osg::notify(osg::WARN) << "DarwinWindowingSystemInterface: could not get # of screens" << std::endl;
169               
170        _displayIds = new CGDirectDisplayID[_displayCount];
171        if( CGGetActiveDisplayList( _displayCount, _displayIds, &_displayCount ) != CGDisplayNoErr )
172                osg::notify(osg::WARN) << "DarwinWindowingSystemInterface: CGGetActiveDisplayList failed" << std::endl;
173       
174        }
175
176/** dtor */
177DarwinWindowingSystemInterface::~DarwinWindowingSystemInterface()
178{
179        if (osg::Referenced::getDeleteHandler())
180        {
181                osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
182                osg::Referenced::getDeleteHandler()->flushAll();
183        }
184
185        if (_displayIds) delete[] _displayIds;
186        _displayIds = NULL;
187}
188
189/** @return a CGDirectDisplayID for a ScreenIdentifier */
190CGDirectDisplayID DarwinWindowingSystemInterface::getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si) {
191        if (si.screenNum < _displayCount)
192                return _displayIds[si.screenNum];
193        else {
194                osg::notify(osg::WARN) << "GraphicsWindowCarbon :: invalid screen # " << si.screenNum << ", returning main-screen instead" << std::endl;
195                return _displayIds[0];
196        }
197}
198
199/** @return count of attached screens */
200unsigned int DarwinWindowingSystemInterface::getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si)
201{
202        return _displayCount;
203}
204
205void DarwinWindowingSystemInterface::getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution)
206{
207        CGDirectDisplayID id = getDisplayID(si);
208        resolution.width = CGDisplayPixelsWide(id);
209        resolution.height = CGDisplayPixelsHigh(id);
210        resolution.colorDepth = CGDisplayBitsPerPixel(id);
211        resolution.refreshRate = getDictDouble (CGDisplayCurrentMode(id), kCGDisplayRefreshRate);        // Not tested
212        if (resolution.refreshRate<0) resolution.refreshRate = 0;
213}
214
215
216void DarwinWindowingSystemInterface::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList) {
217        // Warning! This method has not been tested.
218        resolutionList.clear();
219
220        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
221        CFArrayRef availableModes = CGDisplayAvailableModes(displayID);
222        unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes);
223        for (unsigned int i=0; i<numberOfAvailableModes; ++i) {
224            // look at each mode in the available list
225            CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i);
226            osg::GraphicsContext::ScreenSettings tmpSR;
227
228            long width = getDictLong(mode, kCGDisplayWidth);
229            tmpSR.width = width<=0 ? 0 : width;
230            long height = getDictLong(mode, kCGDisplayHeight);
231            tmpSR.height = height<=0 ? 0 : height;
232            long rate = getDictLong(mode, kCGDisplayRefreshRate);
233            tmpSR.refreshRate = rate<=0 ? 0 : rate;
234            long depth = getDictLong(mode, kCGDisplayBitsPerPixel);
235            tmpSR.colorDepth = depth<=0 ? 0 : depth;
236
237            resolutionList.push_back(tmpSR);
238        }
239    }
240
241/** return the top left coord of a specific screen in global screen space */
242void DarwinWindowingSystemInterface::getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y) {
243        CGRect bounds = CGDisplayBounds( getDisplayID(si) );
244        x = static_cast<int>(bounds.origin.x);
245        y = static_cast<int>(bounds.origin.y);
246       
247        // osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl;
248}
249
250
251
252/** implementation of setScreenResolution */
253bool DarwinWindowingSystemInterface::setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height)
254{
255        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
256       
257        // add next line and on following line replace hard coded depth and refresh rate
258        CGRefreshRate refresh =  getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); 
259        CFDictionaryRef display_mode_values =
260                CGDisplayBestModeForParametersAndRefreshRate(
261                                                displayID,
262                                                CGDisplayBitsPerPixel(displayID),
263                                                width, height, 
264                                                refresh, 
265                                                NULL);
266
267                                                                         
268        CGDisplaySwitchToMode(displayID, display_mode_values);   
269        return true;
270}
271
272/** implementation of setScreenRefreshRate */
273bool DarwinWindowingSystemInterface::setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) {
274       
275        boolean_t  success(false);
276        unsigned width, height;
277        getScreenResolution(screenIdentifier, width, height);
278       
279        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
280       
281        // add next line and on following line replace hard coded depth and refresh rate
282        CFDictionaryRef display_mode_values =
283                CGDisplayBestModeForParametersAndRefreshRate(
284                                                displayID,
285                                                CGDisplayBitsPerPixel(displayID),
286                                                width, height, 
287                                                refreshRate, 
288                                                &success);
289
290                                                                         
291        if (success)
292                CGDisplaySwitchToMode(displayID, display_mode_values);   
293               
294        return (success != 0);
295}
296
297       
298
299
300
301
302
303
304}
Note: See TracBrowser for help on using the browser.