| 205 | | static unsigned int remapOSXKey(unsigned int key, unsigned int rawkey) |
| 206 | | { |
| 207 | | static OSXKeyboardMap s_OSXKeyboardMap; |
| 208 | | return s_OSXKeyboardMap.remapKey(key,rawkey); |
| 209 | | } |
| 210 | | |
| 211 | | |
| 212 | | |
| 213 | | |
| 214 | | #pragma mark * * * MenubarController * * * |
| 215 | | |
| 216 | | /** the MenubarController class checks all open windows if they intersect with the menubar / dock and hide the menubar/dock if necessary */ |
| 217 | | class MenubarController : public osg::Referenced |
| 218 | | { |
| 219 | | |
| 220 | | public: |
| 221 | | MenubarController() : |
| 222 | | osg::Referenced(), |
| 223 | | _list(), |
| 224 | | _menubarShown(false), |
| 225 | | _mutex() |
| 226 | | { |
| 227 | | // the following code will query the system for the available rect on the main-display (typically the displaying showing the menubar + the dock |
| 228 | | |
| 229 | | GDHandle mainScreenDevice; |
| 230 | | |
| 231 | | DMGetGDeviceByDisplayID((DisplayIDType) CGMainDisplayID(), &mainScreenDevice, true); |
| 232 | | GetAvailableWindowPositioningBounds (mainScreenDevice, &_availRect); |
| 233 | | |
| 234 | | // now we need the rect of the main-display including the menubar and the dock |
| 235 | | _mainScreenBounds = CGDisplayBounds( CGMainDisplayID() ); |
| 236 | | |
| 237 | | // hide the menubar initially |
| 238 | | SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); |
| 239 | | } |
| 240 | | |
| 241 | | static MenubarController* instance(); |
| 242 | | |
| 243 | | void attachWindow(GraphicsWindowCarbon* win); |
| 244 | | void update(); |
| 245 | | void detachWindow(GraphicsWindowCarbon* win); |
| 246 | | |
| 247 | | private: |
| 248 | | typedef std::list< osg::observer_ptr< GraphicsWindowCarbon > > WindowList; |
| 249 | | WindowList _list; |
| 250 | | bool _menubarShown; |
| 251 | | Rect _availRect; |
| 252 | | CGRect _mainScreenBounds; |
| 253 | | OpenThreads::Mutex _mutex; |
| 254 | | |
| | 207 | static unsigned int remapCarbonKey(unsigned int key, unsigned int rawkey) |
| | 208 | { |
| | 209 | static CarbonKeyboardMap s_CarbonKeyboardMap; |
| | 210 | return s_CarbonKeyboardMap.remapKey(key,rawkey); |
| | 211 | } |
| | 212 | |
| | 213 | |
| | 214 | class CarbonWindowAdapter : public MenubarController::WindowAdapter { |
| | 215 | public: |
| | 216 | CarbonWindowAdapter(GraphicsWindowCarbon* win) : MenubarController::WindowAdapter(), _win(win) {} |
| | 217 | virtual bool valid() {return (_win.valid() && _win->valid()); } |
| | 218 | virtual void getWindowBounds(CGRect& rect) |
| | 219 | { |
| | 220 | Rect windowBounds; |
| | 221 | OSErr error = GetWindowBounds(_win->getNativeWindowRef(), kWindowStructureRgn, &windowBounds); |
| | 222 | rect.origin.x = windowBounds.left; |
| | 223 | rect.origin.y = windowBounds.top; |
| | 224 | rect.size.width = windowBounds.right - windowBounds.left; |
| | 225 | rect.size.height = windowBounds.bottom - windowBounds.top; |
| | 226 | } |
| | 227 | |
| | 228 | osgViewer::GraphicsWindow* getWindow() { return _win.get(); } |
| | 229 | private: |
| | 230 | osg::observer_ptr<GraphicsWindowCarbon> _win; |
| 256 | | |
| 257 | | |
| 258 | | MenubarController* MenubarController::instance() |
| 259 | | { |
| 260 | | static osg::ref_ptr<MenubarController> s_menubar_controller = new MenubarController(); |
| 261 | | return s_menubar_controller.get(); |
| 262 | | } |
| 263 | | |
| 264 | | |
| 265 | | void MenubarController::attachWindow(GraphicsWindowCarbon* win) |
| 266 | | { |
| 267 | | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| 268 | | _list.push_back(win); |
| 269 | | update(); |
| 270 | | } |
| 271 | | |
| 272 | | |
| 273 | | void MenubarController::detachWindow(GraphicsWindowCarbon* win) |
| 274 | | { |
| 275 | | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| 276 | | for(WindowList::iterator i = _list.begin(); i != _list.end(); ) { |
| 277 | | if ((*i).get() == win) |
| 278 | | i = _list.erase(i); |
| 279 | | else |
| 280 | | ++i; |
| 281 | | } |
| 282 | | update(); |
| 283 | | } |
| 284 | | |
| 285 | | // iterate through all open windows and check, if they intersect the area occupied by the menubar/dock, and if so, hide the menubar/dock |
| 286 | | |
| 287 | | void MenubarController::update() |
| 288 | | { |
| 289 | | OSErr error(noErr); |
| 290 | | unsigned int windowsCoveringMenubarArea = 0; |
| 291 | | unsigned int windowsIntersectingMainScreen = 0; |
| 292 | | for(WindowList::iterator i = _list.begin(); i != _list.end(); ) { |
| 293 | | if ((*i).valid()) { |
| 294 | | GraphicsWindowCarbon* w = (*i).get(); |
| 295 | | Rect windowBounds; |
| 296 | | error = GetWindowBounds(w->getNativeWindowRef(), kWindowStructureRgn, &windowBounds); |
| 297 | | |
| 298 | | bool intersect = !( (_mainScreenBounds.origin.x > windowBounds.right) || |
| 299 | | (_mainScreenBounds.origin.x + _mainScreenBounds.size.width < windowBounds.left) || |
| 300 | | (_mainScreenBounds.origin.y > windowBounds.bottom) || |
| 301 | | (_mainScreenBounds.origin.y + _mainScreenBounds.size.height < windowBounds.top)); |
| 302 | | if (intersect && !error) |
| 303 | | { |
| 304 | | ++windowsIntersectingMainScreen; |
| 305 | | |
| 306 | | // the window intersects the main-screen, does it intersect with the menubar/dock? |
| 307 | | if (((_availRect.top > _mainScreenBounds.origin.y) && (_availRect.top > windowBounds.top)) || |
| 308 | | ((_availRect.left > _mainScreenBounds.origin.x) && (_availRect.left > windowBounds.left)) || |
| 309 | | ((_availRect.right < _mainScreenBounds.origin.x + _mainScreenBounds.size.width) && (_availRect.right < windowBounds.right)) || |
| 310 | | ((_availRect.bottom < _mainScreenBounds.origin.y + _mainScreenBounds.size.height) && (_availRect.bottom < windowBounds.bottom) )) |
| 311 | | { |
| 312 | | ++windowsCoveringMenubarArea; |
| 313 | | } |
| 314 | | } |
| 315 | | |
| 316 | | ++i; |
| 317 | | } |
| 318 | | else |
| 319 | | i= _list.erase(i); |
| 320 | | } |
| 321 | | |
| 322 | | // see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar |
| 323 | | |
| 324 | | if (windowsCoveringMenubarArea && _menubarShown) |
| 325 | | error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); |
| 326 | | |
| 327 | | if (!windowsCoveringMenubarArea && !_menubarShown) |
| 328 | | error = SetSystemUIMode(kUIModeNormal, 0); |
| 329 | | _menubarShown = !windowsCoveringMenubarArea; |
| 330 | | |
| 331 | | // osg::notify(osg::DEBUG_INFO) << "MenubarController:: " << windowsCoveringMenubarArea << " windows covering the menubar/dock area, " << windowsIntersectingMainScreen << " intersecting mainscreen" << std::endl; |
| 332 | | } |
| 333 | | |
| 334 | | |
| 335 | | #pragma mark * * * OSXWindowingSystemInterface * * * |
| 336 | | |
| 337 | | struct OSXCarbonWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface |
| 338 | | { |
| 339 | | |
| 340 | | /** ctor, get a list of all attached displays */ |
| 341 | | OSXCarbonWindowingSystemInterface() : |
| 342 | | _displayCount(0), |
| 343 | | _displayIds(NULL) |
| 344 | | { |
| 345 | | ProcessSerialNumber sn = { 0, kCurrentProcess }; |
| 346 | | TransformProcessType(&sn,kProcessTransformToForegroundApplication); |
| 347 | | SetFrontProcess(&sn); |
| 348 | | |
| 349 | | if( CGGetActiveDisplayList( 0, NULL, &_displayCount ) != CGDisplayNoErr ) |
| 350 | | osg::notify(osg::WARN) << "OSXCarbonWindowingSystemInterface: could not get # of screens" << std::endl; |
| 351 | | |
| 352 | | _displayIds = new CGDirectDisplayID[_displayCount]; |
| 353 | | if( CGGetActiveDisplayList( _displayCount, _displayIds, &_displayCount ) != CGDisplayNoErr ) |
| 354 | | osg::notify(osg::WARN) << "OSXCarbonWindowingSystemInterface: CGGetActiveDisplayList failed" << std::endl; |
| 355 | | |
| 356 | | // register application event handler and AppleEventHandler to get quit-events: |
| 357 | | static const EventTypeSpec menueventSpec = {kEventClassCommand, kEventCommandProcess}; |
| 358 | | OSErr status = InstallEventHandler(GetApplicationEventTarget(), NewEventHandlerUPP(ApplicationEventHandler), 1, &menueventSpec, 0, NULL); |
| 359 | | status = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false); |
| 360 | | } |
| 361 | | |
| 362 | | /** dtor */ |
| 363 | | ~OSXCarbonWindowingSystemInterface() |
| 364 | | { |
| 365 | | if (osg::Referenced::getDeleteHandler()) |
| 366 | | { |
| 367 | | osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); |
| 368 | | osg::Referenced::getDeleteHandler()->flushAll(); |
| 369 | | } |
| 370 | | |
| 371 | | if (_displayIds) delete[] _displayIds; |
| 372 | | _displayIds = NULL; |
| 373 | | } |
| 374 | | |
| 375 | | /** @return a CGDirectDisplayID for a ScreenIdentifier */ |
| 376 | | inline CGDirectDisplayID getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si) { |
| 377 | | if (si.screenNum < _displayCount) |
| 378 | | return _displayIds[si.screenNum]; |
| 379 | | else { |
| 380 | | osg::notify(osg::WARN) << "GraphicsWindowCarbon :: invalid screen # " << si.screenNum << ", returning main-screen instead" << std::endl; |
| 381 | | return _displayIds[0]; |
| 382 | | } |
| 383 | | } |
| 384 | | |
| 385 | | /** @return count of attached screens */ |
| 386 | | virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si) |
| 387 | | { |
| 388 | | return _displayCount; |
| 389 | | } |
| 390 | | |
| 391 | | /** returns the resolution of a specific display */ |
| 392 | | virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution) |
| 393 | | { |
| 394 | | CGDirectDisplayID id = getDisplayID(si); |
| 395 | | resolution.width = CGDisplayPixelsWide(id); |
| 396 | | resolution.height = CGDisplayPixelsHigh(id); |
| 397 | | resolution.colorDepth = CGDisplayBitsPerPixel(id); |
| 398 | | resolution.refreshRate = getDictDouble (CGDisplayCurrentMode(id), kCGDisplayRefreshRate); // Not tested |
| 399 | | if (resolution.refreshRate<0) resolution.refreshRate = 0; |
| 400 | | } |
| 401 | | |
| 402 | | /** return the top left coord of a specific screen in global screen space */ |
| 403 | | void getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y) { |
| 404 | | CGRect bounds = CGDisplayBounds( getDisplayID(si) ); |
| 405 | | x = static_cast<int>(bounds.origin.x); |
| 406 | | y = static_cast<int>(bounds.origin.y); |
| 407 | | |
| 408 | | // osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl; |
| 409 | | } |
| 410 | | |
| 411 | | /** Helper method to get a double value out of a CFDictionary */ |
| 412 | | static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) |
| 413 | | { |
| 414 | | double value; |
| 415 | | CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); |
| 416 | | if (!number_value) // if can't get a number for the dictionary |
| 417 | | return -1; // fail |
| 418 | | if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &value)) // or if cant convert it |
| 419 | | return -1; // fail |
| 420 | | return value; // otherwise return the long value |
| 421 | | } |
| 422 | | |
| 423 | | /** Helper method to get a long value out of a CFDictionary */ |
| 424 | | static long getDictLong(CFDictionaryRef refDict, CFStringRef key) // const void* key? |
| 425 | | { |
| 426 | | long value = 0; |
| 427 | | CFNumberRef number_value = (CFNumberRef)CFDictionaryGetValue(refDict, key); |
| 428 | | if (!number_value) // if can't get a number for the dictionary |
| 429 | | return -1; // fail |
| 430 | | if (!CFNumberGetValue(number_value, kCFNumberLongType, &value)) // or if cant convert it |
| 431 | | return -1; // fail |
| 432 | | return value; |
| 433 | | } |
| 434 | | |
| 435 | | /** implementation of setScreenSettings */ |
| 436 | | virtual bool setScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, const osg::GraphicsContext::ScreenSettings & resolution) |
| 437 | | { |
| 438 | | CGDirectDisplayID displayID = getDisplayID(screenIdentifier); |
| 439 | | |
| 440 | | CGRefreshRate refresh = resolution.refreshRate>0 ? resolution.refreshRate : getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); |
| 441 | | size_t depth = resolution.colorDepth>0 ? resolution.colorDepth : CGDisplayBitsPerPixel(displayID); |
| 442 | | CFDictionaryRef display_mode_values = |
| 443 | | CGDisplayBestModeForParametersAndRefreshRate( |
| 444 | | displayID, |
| 445 | | depth, |
| 446 | | resolution.width, resolution.height, |
| 447 | | refresh, |
| 448 | | NULL); |
| 449 | | |
| 450 | | |
| 451 | | CGDisplaySwitchToMode(displayID, display_mode_values); |
| 452 | | return true; |
| 453 | | } |
| 454 | | |
| 455 | | virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList) { |
| 456 | | // Warning! This method has not been tested. |
| 457 | | resolutionList.clear(); |
| 458 | | |
| 459 | | CGDirectDisplayID displayID = getDisplayID(screenIdentifier); |
| 460 | | CFArrayRef availableModes = CGDisplayAvailableModes(displayID); |
| 461 | | unsigned int numberOfAvailableModes = CFArrayGetCount(availableModes); |
| 462 | | for (unsigned int i=0; i<numberOfAvailableModes; ++i) { |
| 463 | | // look at each mode in the available list |
| 464 | | CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(availableModes, i); |
| 465 | | osg::GraphicsContext::ScreenSettings tmpSR; |
| 466 | | |
| 467 | | long width = getDictLong(mode, kCGDisplayWidth); |
| 468 | | tmpSR.width = width<=0 ? 0 : width; |
| 469 | | long height = getDictLong(mode, kCGDisplayHeight); |
| 470 | | tmpSR.height = height<=0 ? 0 : height; |
| 471 | | long rate = getDictLong(mode, kCGDisplayRefreshRate); |
| 472 | | tmpSR.refreshRate = rate<=0 ? 0 : rate; |
| 473 | | long depth = getDictLong(mode, kCGDisplayBitsPerPixel); |
| 474 | | tmpSR.colorDepth = depth<=0 ? 0 : depth; |
| 475 | | |
| 476 | | resolutionList.push_back(tmpSR); |
| 477 | | } |
| 478 | | } |
| 479 | | |
| 480 | | virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) |
| 481 | | { |
| 482 | | if (traits->pbuffer) |
| 483 | | { |
| 484 | | osg::ref_ptr<osgViewer::PixelBufferCarbon> pbuffer = new PixelBufferCarbon(traits); |
| 485 | | if (pbuffer->valid()) return pbuffer.release(); |
| 486 | | else return 0; |
| 487 | | } |
| 488 | | else |
| 489 | | { |
| 490 | | osg::ref_ptr<osgViewer::GraphicsWindowCarbon> window = new GraphicsWindowCarbon(traits); |
| 491 | | if (window->valid()) return window.release(); |
| 492 | | else return 0; |
| 493 | | } |
| 494 | | } |
| 495 | | |
| 496 | | |
| 497 | | |
| 498 | | private: |
| 499 | | CGDisplayCount _displayCount; |
| 500 | | CGDirectDisplayID* _displayIds; |
| 501 | | }; |
| 502 | | |
| 503 | | } |
| 504 | | |
| 505 | | |
| 506 | | #pragma mark * * * GraphicsWindowCarbon * * * |
| 507 | | |