1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_vcl.hxx" 26 27 #include <stdio.h> 28 29 #include "tools/fsys.hxx" 30 #include "tools/getprocessworkingdir.hxx" 31 #include <tools/solarmutex.hxx> 32 33 #include "osl/process.h" 34 35 #include "rtl/ustrbuf.hxx" 36 37 #include "vcl/svapp.hxx" 38 #include "vcl/window.hxx" 39 #include "vcl/timer.hxx" 40 41 #include "aqua/saldata.hxx" 42 #include "aqua/salinst.h" 43 #include "aqua/salframe.h" 44 #include "aqua/salobj.h" 45 #include "aqua/salsys.h" 46 #include "aqua/salvd.h" 47 #include "aqua/salbmp.h" 48 #include "aqua/salprn.h" 49 #include "aqua/saltimer.h" 50 #include "aqua/vclnsapp.h" 51 52 #include "print.h" 53 #include "impbmp.hxx" 54 #include "salimestatus.hxx" 55 56 #include <comphelper/processfactory.hxx> 57 58 #include <com/sun/star/beans/XPropertySet.hpp> 59 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 60 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp> 61 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp> 62 #include <com/sun/star/uno/XComponentContext.hpp> 63 64 #include "premac.h" 65 #include <Foundation/Foundation.h> 66 #include <ApplicationServices/ApplicationServices.h> 67 #import "apple_remote/RemoteMainController.h" 68 #include "apple_remote/RemoteControl.h" 69 #include "postmac.h" 70 71 using namespace std; 72 using namespace ::com::sun::star; 73 74 extern sal_Bool ImplSVMain(); 75 76 static sal_Bool* gpbInit = 0; 77 static NSMenu* pDockMenu = nil; 78 static bool bNoSVMain = true; 79 static bool bLeftMain = false; 80 // ----------------------------------------------------------------------- 81 82 class AquaDelayedSettingsChanged : public Timer 83 { 84 bool mbInvalidate; 85 public: 86 AquaDelayedSettingsChanged( bool bInvalidate ) : 87 mbInvalidate( bInvalidate ) 88 { 89 } 90 91 virtual void Timeout() 92 { 93 SalData* pSalData = GetSalData(); 94 if( ! pSalData->maFrames.empty() ) 95 pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL ); 96 97 if( mbInvalidate ) 98 { 99 for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin(); 100 it != pSalData->maFrames.end(); ++it ) 101 { 102 if( (*it)->mbShown ) 103 (*it)->SendPaintEvent( NULL ); 104 } 105 } 106 Stop(); 107 delete this; 108 } 109 }; 110 111 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate ) 112 { 113 vos::OGuard aGuard( *mpSalYieldMutex ); 114 AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate ); 115 pTimer->SetTimeout( 50 ); 116 pTimer->Start(); 117 } 118 119 120 // the AppEventList must be available before any SalData/SalInst/etc. objects are ready 121 typedef std::list<const ApplicationEvent*> AppEventList; 122 AppEventList AquaSalInstance::aAppEventList; 123 124 NSMenu* AquaSalInstance::GetDynamicDockMenu() 125 { 126 if( ! pDockMenu && ! bLeftMain ) 127 pDockMenu = [[NSMenu alloc] initWithTitle: @""]; 128 return pDockMenu; 129 } 130 131 bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg ) 132 { 133 sal_uInt32 nArgs = osl_getCommandArgCount(); 134 for( sal_uInt32 i = 0; i < nArgs; i++ ) 135 { 136 rtl::OUString aArg; 137 osl_getCommandArg( i, &aArg.pData ); 138 if( aArg.equals( rArg ) ) 139 return true; 140 } 141 return false; 142 } 143 144 145 // initialize the cocoa VCL_NSApplication object 146 // returns an NSAutoreleasePool that must be released when the event loop begins 147 static void initNSApp() 148 { 149 // create our cocoa NSApplication 150 [VCL_NSApplication sharedApplication]; 151 152 SalData::ensureThreadAutoreleasePool(); 153 154 // put cocoa into multithreaded mode 155 [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil]; 156 157 // activate our delegate methods 158 [NSApp setDelegate: NSApp]; 159 160 [[NSNotificationCenter defaultCenter] addObserver: NSApp 161 selector: @selector(systemColorsChanged:) 162 name: NSSystemColorsDidChangeNotification 163 object: nil ]; 164 [[NSNotificationCenter defaultCenter] addObserver: NSApp 165 selector: @selector(screenParametersChanged:) 166 name: NSApplicationDidChangeScreenParametersNotification 167 object: nil ]; 168 // add observers for some settings changes that affect vcl's settings 169 // scrollbar variant 170 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 171 selector: @selector(scrollbarVariantChanged:) 172 name: @"AppleAquaScrollBarVariantChanged" 173 object: nil ]; 174 // scrollbar page behavior ("jump to here" or not) 175 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 176 selector: @selector(scrollbarSettingsChanged:) 177 name: @"AppleNoRedisplayAppearancePreferenceChanged" 178 object: nil ]; 179 180 // get System Version and store the value in GetSalData()->mnSystemVersion 181 SInt32 systemVersion = OSX_VER_LION; // initialize with the minimal requirement 182 const OSErr err = Gestalt( gestaltSystemVersion, &systemVersion); 183 if( err == noErr ) 184 { 185 GetSalData()->mnSystemVersion = systemVersion; 186 #if OSL_DEBUG_LEVEL > 1 187 fprintf( stderr, "OSX System Version 0x%04x\n", (unsigned int)systemVersion); 188 #endif 189 } 190 else 191 NSLog(@"Unable to obtain system version: %ld", (long)err); 192 193 GetSalData()->mpAppleRemoteMainController = [[AppleRemoteMainController alloc] init]; 194 195 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 196 selector: @selector(applicationWillBecomeActive:) 197 name: @"AppleRemoteWillBecomeActive" 198 object: nil ]; 199 200 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp 201 selector: @selector(applicationWillResignActive:) 202 name: @"AppleRemoteWillResignActive" 203 object: nil ]; 204 205 if( ImplGetSVData()->mbIsTestTool ) 206 [NSApp activateIgnoringOtherApps: YES]; 207 } 208 209 sal_Bool ImplSVMainHook( sal_Bool * pbInit ) 210 { 211 gpbInit = pbInit; 212 213 bNoSVMain = false; 214 initNSApp(); 215 216 rtl::OUString aExeURL, aExe; 217 osl_getExecutableFile( &aExeURL.pData ); 218 osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData ); 219 rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) ); 220 221 #ifdef DEBUG 222 aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" ); 223 const char* pArgv[] = { aByteExe.getStr(), NULL }; 224 NSApplicationMain( 3, pArgv ); 225 #else 226 const char* pArgv[] = { aByteExe.getStr(), NULL }; 227 NSApplicationMain( 1, pArgv ); 228 #endif 229 230 return TRUE; // indicate that ImplSVMainHook is implemented 231 } 232 233 // ======================================================================= 234 235 void SalAbort( const XubString& rErrorText ) 236 { 237 if( !rErrorText.Len() ) 238 fprintf( stderr, "Application Error " ); 239 else 240 fprintf( stderr, "%s ", 241 ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() ); 242 abort(); 243 } 244 245 // ----------------------------------------------------------------------- 246 247 void InitSalData() 248 { 249 SalData *pSalData = new SalData; 250 SetSalData( pSalData ); 251 } 252 253 // ----------------------------------------------------------------------- 254 255 const ::rtl::OUString& SalGetDesktopEnvironment() 256 { 257 static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" )); 258 return aDesktopEnvironment; 259 } 260 261 // ----------------------------------------------------------------------- 262 263 void DeInitSalData() 264 { 265 SalData *pSalData = GetSalData(); 266 if( pSalData->mpStatusItem ) 267 { 268 [pSalData->mpStatusItem release]; 269 pSalData->mpStatusItem = nil; 270 } 271 delete pSalData; 272 SetSalData( NULL ); 273 } 274 275 // ----------------------------------------------------------------------- 276 277 extern "C" { 278 #include <crt_externs.h> 279 } 280 281 // ----------------------------------------------------------------------- 282 283 void InitSalMain() 284 { 285 rtl::OUString urlWorkDir; 286 rtl_uString *sysWorkDir = NULL; 287 if (tools::getProcessWorkingDir(&urlWorkDir)) 288 { 289 oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir); 290 if (err2 == osl_File_E_None) 291 { 292 ByteString aPath( getenv( "PATH" ) ); 293 ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) ); 294 ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) ); 295 ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() ); 296 ByteString aTmpPath; 297 // Get absolute path of command's directory 298 if ( aCmdPath.Len() ) { 299 DirEntry aCmdDirEntry( aCmdPath ); 300 aCmdDirEntry.ToAbs(); 301 aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US ); 302 } 303 // Assign to PATH environment variable 304 if ( aCmdPath.Len() ) 305 { 306 aTmpPath = aCmdPath; 307 if ( aPath.Len() ) 308 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 309 aTmpPath += aPath; 310 setenv( "PATH", aTmpPath.GetBuffer(), TRUE ); 311 } 312 // Assign to STAR_RESOURCEPATH environment variable 313 if ( aCmdPath.Len() ) 314 { 315 aTmpPath = aCmdPath; 316 if ( aResPath.Len() ) 317 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 318 aTmpPath += aResPath; 319 setenv( "STAR_RESOURCEPATH", aTmpPath.GetBuffer(), TRUE ); 320 } 321 // Assign to DYLD_LIBRARY_PATH environment variable 322 if ( aCmdPath.Len() ) 323 { 324 aTmpPath = aCmdPath; 325 if ( aLibPath.Len() ) 326 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US ); 327 aTmpPath += aLibPath; 328 setenv( "DYLD_LIBRARY_PATH", aTmpPath.GetBuffer(), TRUE ); 329 } 330 } 331 } 332 } 333 334 // ----------------------------------------------------------------------- 335 336 void DeInitSalMain() 337 { 338 } 339 340 // ======================================================================= 341 342 SalYieldMutex::SalYieldMutex() 343 { 344 mnCount = 0; 345 mnThreadId = 0; 346 } 347 348 void SalYieldMutex::acquire() 349 { 350 OMutex::acquire(); 351 mnThreadId = vos::OThread::getCurrentIdentifier(); 352 mnCount++; 353 } 354 355 void SalYieldMutex::release() 356 { 357 if ( mnThreadId == vos::OThread::getCurrentIdentifier() ) 358 { 359 if ( mnCount == 1 ) 360 mnThreadId = 0; 361 mnCount--; 362 } 363 OMutex::release(); 364 } 365 366 sal_Bool SalYieldMutex::tryToAcquire() 367 { 368 if ( OMutex::tryToAcquire() ) 369 { 370 mnThreadId = vos::OThread::getCurrentIdentifier(); 371 mnCount++; 372 return sal_True; 373 } 374 else 375 return sal_False; 376 } 377 378 // ----------------------------------------------------------------------- 379 380 // some convenience functions regarding the yield mutex, aka solar mutex 381 382 sal_Bool ImplSalYieldMutexTryToAcquire() 383 { 384 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 385 if ( pInst ) 386 return pInst->mpSalYieldMutex->tryToAcquire(); 387 else 388 return FALSE; 389 } 390 391 void ImplSalYieldMutexAcquire() 392 { 393 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 394 if ( pInst ) 395 pInst->mpSalYieldMutex->acquire(); 396 } 397 398 void ImplSalYieldMutexRelease() 399 { 400 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance; 401 if ( pInst ) 402 pInst->mpSalYieldMutex->release(); 403 } 404 405 // ======================================================================= 406 407 SalInstance* CreateSalInstance() 408 { 409 // this is the case for not using SVMain 410 // not so good 411 if( bNoSVMain ) 412 initNSApp(); 413 414 SalData* pSalData = GetSalData(); 415 DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" ); 416 AquaSalInstance* pInst = new AquaSalInstance; 417 418 // init instance (only one instance in this version !!!) 419 pSalData->mpFirstInstance = pInst; 420 // this one is for outside AquaSalInstance::Yield 421 SalData::ensureThreadAutoreleasePool(); 422 // no focus rects on NWF aqua 423 ImplGetSVData()->maNWFData.mbNoFocusRects = true; 424 ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true; 425 ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true; 426 ImplGetSVData()->maNWFData.mbCenteredTabs = true; 427 ImplGetSVData()->maNWFData.mbProgressNeedsErase = true; 428 ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true; 429 ImplGetSVData()->maNWFData.mnStatusBarLowerRightOffset = 10; 430 ImplGetSVData()->maGDIData.mbNoXORClipping = true; 431 ImplGetSVData()->maWinData.mbNoSaveBackground = true; 432 433 return pInst; 434 } 435 436 // ----------------------------------------------------------------------- 437 438 void DestroySalInstance( SalInstance* pInst ) 439 { 440 delete pInst; 441 } 442 443 // ----------------------------------------------------------------------- 444 445 AquaSalInstance::AquaSalInstance() 446 { 447 mpSalYieldMutex = new SalYieldMutex; 448 mpSalYieldMutex->acquire(); 449 ::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex ); 450 maMainThread = vos::OThread::getCurrentIdentifier(); 451 mbWaitingYield = false; 452 maUserEventListMutex = osl_createMutex(); 453 mnActivePrintJobs = 0; 454 maWaitingYieldCond = osl_createCondition(); 455 } 456 457 // ----------------------------------------------------------------------- 458 459 AquaSalInstance::~AquaSalInstance() 460 { 461 ::tools::SolarMutex::SetSolarMutex( 0 ); 462 mpSalYieldMutex->release(); 463 delete mpSalYieldMutex; 464 osl_destroyMutex( maUserEventListMutex ); 465 osl_destroyCondition( maWaitingYieldCond ); 466 } 467 468 // ----------------------------------------------------------------------- 469 470 void AquaSalInstance::wakeupYield() 471 { 472 // wakeup :Yield 473 if( mbWaitingYield ) 474 { 475 SalData::ensureThreadAutoreleasePool(); 476 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined 477 location: NSZeroPoint 478 modifierFlags: 0 479 timestamp: 0 480 windowNumber: 0 481 context: nil 482 subtype: AquaSalInstance::YieldWakeupEvent 483 data1: 0 484 data2: 0 ]; 485 if( pEvent ) 486 [NSApp postEvent: pEvent atStart: NO]; 487 } 488 } 489 490 // ----------------------------------------------------------------------- 491 492 void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, sal_uInt16 nType, void* pData ) 493 { 494 osl_acquireMutex( maUserEventListMutex ); 495 maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) ); 496 osl_releaseMutex( maUserEventListMutex ); 497 498 // notify main loop that an event has arrived 499 wakeupYield(); 500 } 501 502 // ----------------------------------------------------------------------- 503 504 vos::IMutex* AquaSalInstance::GetYieldMutex() 505 { 506 return mpSalYieldMutex; 507 } 508 509 // ----------------------------------------------------------------------- 510 511 sal_uLong AquaSalInstance::ReleaseYieldMutex() 512 { 513 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 514 if ( pYieldMutex->GetThreadId() == 515 vos::OThread::getCurrentIdentifier() ) 516 { 517 sal_uLong nCount = pYieldMutex->GetAcquireCount(); 518 sal_uLong n = nCount; 519 while ( n ) 520 { 521 pYieldMutex->release(); 522 n--; 523 } 524 525 return nCount; 526 } 527 else 528 return 0; 529 } 530 531 // ----------------------------------------------------------------------- 532 533 void AquaSalInstance::AcquireYieldMutex( sal_uLong nCount ) 534 { 535 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 536 while ( nCount ) 537 { 538 pYieldMutex->acquire(); 539 nCount--; 540 } 541 } 542 543 // ----------------------------------------------------------------------- 544 545 bool AquaSalInstance::CheckYieldMutex() 546 { 547 bool bRet = true; 548 549 SalYieldMutex* pYieldMutex = mpSalYieldMutex; 550 if ( pYieldMutex->GetThreadId() != 551 vos::OThread::getCurrentIdentifier() ) 552 { 553 bRet = false; 554 } 555 556 return bRet; 557 } 558 559 // ----------------------------------------------------------------------- 560 561 bool AquaSalInstance::isNSAppThread() const 562 { 563 return vos::OThread::getCurrentIdentifier() == maMainThread; 564 } 565 566 // ----------------------------------------------------------------------- 567 568 void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent ) 569 { 570 switch( [pEvent subtype] ) 571 { 572 case AppStartTimerEvent: 573 AquaSalTimer::handleStartTimerEvent( pEvent ); 574 break; 575 case AppEndLoopEvent: 576 [NSApp stop: NSApp]; 577 break; 578 case AppExecuteSVMain: 579 { 580 sal_Bool bResult = ImplSVMain(); 581 if( gpbInit ) 582 *gpbInit = bResult; 583 [NSApp stop: NSApp]; 584 bLeftMain = true; 585 if( pDockMenu ) 586 { 587 [pDockMenu release]; 588 pDockMenu = nil; 589 } 590 } 591 break; 592 case AppleRemoteEvent: 593 { 594 sal_Int16 nCommand = 0; 595 SalData* pSalData = GetSalData(); 596 bool bIsFullScreenMode = false; 597 598 std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin(); 599 for(; it != pSalData->maFrames.end(); ++it ) 600 { 601 if( (*it)->mbFullScreen ) 602 bIsFullScreenMode = true; 603 } 604 605 switch ([pEvent data1]) 606 { 607 case kRemoteButtonPlay: 608 nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY; 609 break; 610 611 // kept for experimentation purpose (scheduled for future implementation) 612 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break; 613 614 case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break; 615 616 case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break; 617 618 case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break; 619 620 case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break; 621 622 case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break; 623 624 case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break; 625 626 case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break; 627 628 case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break; 629 630 // FIXME : not detected 631 case kRemoteButtonPlus_Hold: 632 case kRemoteButtonMinus_Hold: 633 break; 634 635 default: 636 break; 637 } 638 AquaSalFrame* pFrame = pSalData->maFrames.front(); 639 Window* pWindow = pFrame ? pFrame->GetWindow() : NULL; 640 641 if( pWindow ) 642 { 643 const Point aPoint; 644 CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand ); 645 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt ); 646 647 if ( !ImplCallPreNotify( aNCmdEvt ) ) 648 pWindow->Command( aCEvt ); 649 } 650 651 } 652 break; 653 654 case YieldWakeupEvent: 655 // do nothing, fall out of Yield 656 break; 657 658 default: 659 DBG_ERROR( "unhandled NSApplicationDefined event" ); 660 break; 661 }; 662 } 663 664 // ----------------------------------------------------------------------- 665 666 class ReleasePoolHolder 667 { 668 NSAutoreleasePool* mpPool; 669 public: 670 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {} 671 ~ReleasePoolHolder() { [mpPool release]; } 672 }; 673 674 void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents ) 675 { 676 // ensure that the per thread autorelease pool is top level and 677 // will therefore not be destroyed by cocoa implicitly 678 SalData::ensureThreadAutoreleasePool(); 679 680 // NSAutoreleasePool documentation suggests we should have 681 // an own pool for each yield level 682 ReleasePoolHolder aReleasePool; 683 684 // Release all locks so that we don't deadlock when we pull pending 685 // events from the event queue 686 bool bDispatchUser = true; 687 while( bDispatchUser ) 688 { 689 sal_uLong nCount = ReleaseYieldMutex(); 690 691 // get one user event 692 osl_acquireMutex( maUserEventListMutex ); 693 SalUserEvent aEvent( NULL, NULL, 0 ); 694 if( ! maUserEvents.empty() ) 695 { 696 aEvent = maUserEvents.front(); 697 maUserEvents.pop_front(); 698 } 699 else 700 bDispatchUser = false; 701 osl_releaseMutex( maUserEventListMutex ); 702 703 AcquireYieldMutex( nCount ); 704 705 // dispatch it 706 if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) ) 707 { 708 aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData ); 709 osl_setCondition( maWaitingYieldCond ); 710 // return if only one event is asked for 711 if( ! bHandleAllCurrentEvents ) 712 return; 713 } 714 } 715 716 // handle cocoa event queue 717 // cocoa events mye be only handled in the thread the NSApp was created 718 if( isNSAppThread() && mnActivePrintJobs == 0 ) 719 { 720 // we need to be woken up by a cocoa-event 721 // if a user event should be posted by the event handling below 722 bool bOldWaitingYield = mbWaitingYield; 723 mbWaitingYield = bWait; 724 725 // handle available events 726 NSEvent* pEvent = nil; 727 bool bHadEvent = false; 728 do 729 { 730 sal_uLong nCount = ReleaseYieldMutex(); 731 732 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil 733 inMode: NSDefaultRunLoopMode dequeue: YES]; 734 if( pEvent ) 735 { 736 [NSApp sendEvent: pEvent]; 737 bHadEvent = true; 738 } 739 [NSApp updateWindows]; 740 741 AcquireYieldMutex( nCount ); 742 } while( bHandleAllCurrentEvents && pEvent ); 743 744 // if we had no event yet, wait for one if requested 745 if( bWait && ! bHadEvent ) 746 { 747 sal_uLong nCount = ReleaseYieldMutex(); 748 749 NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture]; 750 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt 751 inMode: NSDefaultRunLoopMode dequeue: YES]; 752 if( pEvent ) 753 [NSApp sendEvent: pEvent]; 754 [NSApp updateWindows]; 755 756 AcquireYieldMutex( nCount ); 757 758 // #i86581# 759 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then 760 // fixes the problem even seems to set the correct next firing date 761 // Why oh why ? 762 if( ! pEvent && AquaSalTimer::pRunningTimer ) 763 { 764 // this cause crashes on MacOSX 10.4 765 // [AquaSalTimer::pRunningTimer fire]; 766 ImplGetSVData()->mpSalTimer->CallCallback(); 767 } 768 } 769 770 mbWaitingYield = bOldWaitingYield; 771 772 // collect update rectangles 773 const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames ); 774 for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it ) 775 { 776 if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() ) 777 { 778 (*it)->Flush( (*it)->maInvalidRect ); 779 (*it)->maInvalidRect.SetEmpty(); 780 } 781 } 782 osl_setCondition( maWaitingYieldCond ); 783 } 784 else if( bWait ) 785 { 786 // #i103162# 787 // wait until any thread (most likely the main thread) 788 // has dispatched an event, cop out at 100 ms 789 sal_uLong nCount; 790 TimeValue aVal = { 0, 100000000 }; 791 osl_resetCondition( maWaitingYieldCond ); 792 nCount = ReleaseYieldMutex(); 793 osl_waitCondition( maWaitingYieldCond, &aVal ); 794 AcquireYieldMutex( nCount ); 795 } 796 // we get some apple events way too early 797 // before the application is ready to handle them, 798 // so their corresponding application events need to be delayed 799 // now is a good time to handle at least one of them 800 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute ) 801 { 802 // make sure that only one application event is active at a time 803 static bool bInAppEvent = false; 804 if( !bInAppEvent ) 805 { 806 bInAppEvent = true; 807 // get the next delayed application event 808 const ApplicationEvent* pAppEvent = aAppEventList.front(); 809 aAppEventList.pop_front(); 810 // handle one application event (no recursion) 811 const ImplSVData* pSVData = ImplGetSVData(); 812 pSVData->mpApp->AppEvent( *pAppEvent ); 813 delete pAppEvent; 814 // allow the next delayed application event 815 bInAppEvent = false; 816 } 817 } 818 } 819 820 // ----------------------------------------------------------------------- 821 822 bool AquaSalInstance::AnyInput( sal_uInt16 nType ) 823 { 824 if( nType & INPUT_APPEVENT ) 825 { 826 if( ! aAppEventList.empty() ) 827 return true; 828 if( nType == INPUT_APPEVENT ) 829 return false; 830 } 831 832 if( nType & INPUT_TIMER ) 833 { 834 if( AquaSalTimer::pRunningTimer ) 835 { 836 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate]; 837 if( pDt && [pDt timeIntervalSinceNow] < 0 ) 838 { 839 return true; 840 } 841 } 842 } 843 844 unsigned/*NSUInteger*/ nEventMask = 0; 845 if( nType & INPUT_MOUSE) 846 nEventMask |= 847 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask | 848 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask | 849 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask | 850 NSScrollWheelMask | 851 // NSMouseMovedMask | 852 NSMouseEnteredMask | NSMouseExitedMask; 853 if( nType & INPUT_KEYBOARD) 854 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask; 855 if( nType & INPUT_OTHER) 856 nEventMask |= NSTabletPoint; 857 // TODO: INPUT_PAINT / more INPUT_OTHER 858 if( !nType) 859 return false; 860 861 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil 862 inMode: NSDefaultRunLoopMode dequeue: NO]; 863 return (pEvent != NULL); 864 } 865 866 // ----------------------------------------------------------------------- 867 868 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData*, sal_uLong /*nSalFrameStyle*/ ) 869 { 870 return NULL; 871 } 872 873 // ----------------------------------------------------------------------- 874 875 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle ) 876 { 877 SalData::ensureThreadAutoreleasePool(); 878 879 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle ); 880 return pFrame; 881 } 882 883 // ----------------------------------------------------------------------- 884 885 void AquaSalInstance::DestroyFrame( SalFrame* pFrame ) 886 { 887 delete pFrame; 888 } 889 890 // ----------------------------------------------------------------------- 891 892 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, sal_Bool /* bShow */ ) 893 { 894 // SystemWindowData is meaningless on Mac OS X 895 AquaSalObject *pObject = NULL; 896 897 if ( pParent ) 898 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) ); 899 900 return pObject; 901 } 902 903 // ----------------------------------------------------------------------- 904 905 void AquaSalInstance::DestroyObject( SalObject* pObject ) 906 { 907 delete ( pObject ); 908 } 909 910 // ----------------------------------------------------------------------- 911 912 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 913 { 914 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) ); 915 } 916 917 // ----------------------------------------------------------------------- 918 919 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter ) 920 { 921 delete pPrinter; 922 } 923 924 // ----------------------------------------------------------------------- 925 926 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 927 { 928 NSArray* pNames = [NSPrinter printerNames]; 929 NSArray* pTypes = [NSPrinter printerTypes]; 930 unsigned int nNameCount = pNames ? [pNames count] : 0; 931 unsigned int nTypeCount = pTypes ? [pTypes count] : 0; 932 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" ); 933 for( unsigned int i = 0; i < nNameCount; i++ ) 934 { 935 NSString* pName = [pNames objectAtIndex: i]; 936 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil; 937 if( pName ) 938 { 939 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 940 pInfo->maPrinterName = GetOUString( pName ); 941 if( pType ) 942 pInfo->maDriver = GetOUString( pType ); 943 pInfo->mnStatus = 0; 944 pInfo->mnJobs = 0; 945 pInfo->mpSysData = NULL; 946 947 pList->Add( pInfo ); 948 } 949 } 950 } 951 952 // ----------------------------------------------------------------------- 953 954 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 955 { 956 } 957 958 // ----------------------------------------------------------------------- 959 960 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 961 { 962 delete pInfo; 963 } 964 965 // ----------------------------------------------------------------------- 966 967 XubString AquaSalInstance::GetDefaultPrinter() 968 { 969 // #i113170# may not be the main thread if called from UNO API 970 SalData::ensureThreadAutoreleasePool(); 971 972 if( ! maDefaultPrinter.getLength() ) 973 { 974 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo]; 975 DBG_ASSERT( pPI, "no print info" ); 976 if( pPI ) 977 { 978 NSPrinter* pPr = [pPI printer]; 979 DBG_ASSERT( pPr, "no printer in default info" ); 980 if( pPr ) 981 { 982 NSString* pDefName = [pPr name]; 983 DBG_ASSERT( pDefName, "printer has no name" ); 984 maDefaultPrinter = GetOUString( pDefName ); 985 } 986 } 987 } 988 return maDefaultPrinter; 989 } 990 991 // ----------------------------------------------------------------------- 992 993 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 994 ImplJobSetup* pSetupData ) 995 { 996 // #i113170# may not be the main thread if called from UNO API 997 SalData::ensureThreadAutoreleasePool(); 998 999 SalInfoPrinter* pNewInfoPrinter = NULL; 1000 if( pQueueInfo ) 1001 { 1002 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo ); 1003 if( pSetupData ) 1004 pNewInfoPrinter->SetPrinterData( pSetupData ); 1005 } 1006 1007 return pNewInfoPrinter; 1008 } 1009 1010 // ----------------------------------------------------------------------- 1011 1012 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 1013 { 1014 // #i113170# may not be the main thread if called from UNO API 1015 SalData::ensureThreadAutoreleasePool(); 1016 1017 delete pPrinter; 1018 } 1019 1020 // ----------------------------------------------------------------------- 1021 1022 SalSystem* AquaSalInstance::CreateSystem() 1023 { 1024 return new AquaSalSystem(); 1025 } 1026 1027 // ----------------------------------------------------------------------- 1028 1029 void AquaSalInstance::DestroySystem( SalSystem* pSystem ) 1030 { 1031 delete pSystem; 1032 } 1033 1034 // ----------------------------------------------------------------------- 1035 1036 void AquaSalInstance::SetEventCallback( void*, bool(*)(void*,void*,int) ) 1037 { 1038 } 1039 1040 // ----------------------------------------------------------------------- 1041 1042 void AquaSalInstance::SetErrorEventCallback( void*, bool(*)(void*,void*,int) ) 1043 { 1044 } 1045 1046 // ----------------------------------------------------------------------- 1047 1048 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes ) 1049 { 1050 rReturnedBytes = 1; 1051 rReturnedType = AsciiCString; 1052 return (void*)""; 1053 } 1054 1055 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts 1056 // to UTF-8 before encoding non ascii characters, which is not what other apps expect. 1057 static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl) 1058 { 1059 rtl::OUString extUrl; 1060 1061 uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory(); 1062 if (sm.is()) 1063 { 1064 uno::Reference< beans::XPropertySet > pset; 1065 sm->queryInterface( getCppuType( &pset )) >>= pset; 1066 if (pset.is()) 1067 { 1068 uno::Reference< uno::XComponentContext > context; 1069 static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ); 1070 pset->getPropertyValue(DEFAULT_CONTEXT) >>= context; 1071 if (context.is()) 1072 extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl); 1073 } 1074 } 1075 return extUrl; 1076 } 1077 1078 // #i104525# many versions of OSX have problems with some URLs: 1079 // when an app requests OSX to add one of these URLs to the "Recent Items" list 1080 // then this app gets killed (TextEdit, Preview, etc. and also OOo) 1081 static bool isDangerousUrl( const rtl::OUString& rUrl ) 1082 { 1083 // use a heuristic that detects all known cases since there is no official comment 1084 // on the exact impact and root cause of the OSX bug 1085 const int nLen = rUrl.getLength(); 1086 const sal_Unicode* p = rUrl.getStr(); 1087 for( int i = 0; i < nLen-3; ++i, ++p ) { 1088 if( p[0] != '%' ) 1089 continue; 1090 // escaped percent? 1091 if( (p[1] == '2') && (p[2] == '5') ) 1092 return true; 1093 // escapes are considered to be UTF-8 encoded 1094 // => check for invalid UTF-8 leading byte 1095 if( (p[1] != 'f') && (p[1] != 'F') ) 1096 continue; 1097 int cLowNibble = p[2]; 1098 if( (cLowNibble >= '0' ) && (cLowNibble <= '9')) 1099 return false; 1100 if( cLowNibble >= 'a' ) 1101 cLowNibble -= 'a' - 'A'; 1102 if( (cLowNibble < 'A') || (cLowNibble >= 'C')) 1103 return true; 1104 } 1105 1106 return false; 1107 } 1108 1109 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/) 1110 { 1111 // Convert file URL for external use (see above) 1112 rtl::OUString externalUrl = translateToExternalUrl(rFileUrl); 1113 if( 0 == externalUrl.getLength() ) 1114 externalUrl = rFileUrl; 1115 1116 if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) ) 1117 { 1118 NSString* pString = CreateNSString( externalUrl ); 1119 NSURL* pURL = [NSURL URLWithString: pString]; 1120 1121 if( pURL ) 1122 { 1123 NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController]; 1124 [pCtrl noteNewRecentDocumentURL: pURL]; 1125 } 1126 if( pString ) 1127 [pString release]; 1128 } 1129 } 1130 1131 1132 // ----------------------------------------------------------------------- 1133 1134 SalTimer* AquaSalInstance::CreateSalTimer() 1135 { 1136 return new AquaSalTimer(); 1137 } 1138 1139 // ----------------------------------------------------------------------- 1140 1141 SalSystem* AquaSalInstance::CreateSalSystem() 1142 { 1143 return new AquaSalSystem(); 1144 } 1145 1146 // ----------------------------------------------------------------------- 1147 1148 SalBitmap* AquaSalInstance::CreateSalBitmap() 1149 { 1150 return new AquaSalBitmap(); 1151 } 1152 1153 // ----------------------------------------------------------------------- 1154 1155 SalSession* AquaSalInstance::CreateSalSession() 1156 { 1157 return NULL; 1158 } 1159 1160 // ----------------------------------------------------------------------- 1161 1162 class MacImeStatus : public SalI18NImeStatus 1163 { 1164 public: 1165 MacImeStatus() {} 1166 virtual ~MacImeStatus() {} 1167 1168 // asks whether there is a status window available 1169 // to toggle into menubar 1170 virtual bool canToggle() { return false; } 1171 virtual void toggle() {} 1172 }; 1173 1174 // ----------------------------------------------------------------------- 1175 1176 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus() 1177 { 1178 return new MacImeStatus(); 1179 } 1180 1181 // YieldMutexReleaser 1182 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 ) 1183 { 1184 SalData* pSalData = GetSalData(); 1185 if( ! pSalData->mpFirstInstance->isNSAppThread() ) 1186 { 1187 SalData::ensureThreadAutoreleasePool(); 1188 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex(); 1189 } 1190 } 1191 1192 YieldMutexReleaser::~YieldMutexReleaser() 1193 { 1194 if( mnCount != 0 ) 1195 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount ); 1196 } 1197 1198 ////////////////////////////////////////////////////////////// 1199 rtl::OUString GetOUString( CFStringRef rStr ) 1200 { 1201 if( rStr == 0 ) 1202 return rtl::OUString(); 1203 CFIndex nLength = CFStringGetLength( rStr ); 1204 if( nLength == 0 ) 1205 return rtl::OUString(); 1206 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr ); 1207 if( pConstStr ) 1208 return rtl::OUString( pConstStr, nLength ); 1209 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) ); 1210 CFRange aRange = { 0, nLength }; 1211 CFStringGetCharacters( rStr, aRange, pStr ); 1212 rtl::OUString aRet( pStr, nLength ); 1213 rtl_freeMemory( pStr ); 1214 return aRet; 1215 } 1216 1217 rtl::OUString GetOUString( NSString* pStr ) 1218 { 1219 if( ! pStr ) 1220 return rtl::OUString(); 1221 int nLen = [pStr length]; 1222 if( nLen == 0 ) 1223 return rtl::OUString(); 1224 1225 rtl::OUStringBuffer aBuf( nLen+1 ); 1226 aBuf.setLength( nLen ); 1227 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())]; 1228 return aBuf.makeStringAndClear(); 1229 } 1230 1231 CFStringRef CreateCFString( const rtl::OUString& rStr ) 1232 { 1233 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() ); 1234 } 1235 1236 NSString* CreateNSString( const rtl::OUString& rStr ) 1237 { 1238 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()]; 1239 } 1240 1241 CGImageRef CreateCGImage( const Image& rImage ) 1242 { 1243 BitmapEx aBmpEx( rImage.GetBitmapEx() ); 1244 Bitmap aBmp( aBmpEx.GetBitmap() ); 1245 1246 if( ! aBmp || ! aBmp.ImplGetImpBitmap() ) 1247 return NULL; 1248 1249 // simple case, no transparency 1250 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap()); 1251 1252 if( ! pSalBmp ) 1253 return NULL; 1254 1255 CGImageRef xImage = NULL; 1256 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) ) 1257 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1258 else if( aBmpEx.IsAlpha() ) 1259 { 1260 AlphaMask aAlphaMask( aBmpEx.GetAlpha() ); 1261 Bitmap aMask( aAlphaMask.GetBitmap() ); 1262 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1263 if( pMaskBmp ) 1264 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1265 else 1266 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1267 } 1268 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP ) 1269 { 1270 Bitmap aMask( aBmpEx.GetMask() ); 1271 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap()); 1272 if( pMaskBmp ) 1273 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1274 else 1275 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight ); 1276 } 1277 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR ) 1278 { 1279 Color aTransColor( aBmpEx.GetTransparentColor() ); 1280 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() ); 1281 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor ); 1282 } 1283 1284 return xImage; 1285 } 1286 1287 NSImage* CreateNSImage( const Image& rImage ) 1288 { 1289 CGImageRef xImage = CreateCGImage( rImage ); 1290 1291 if( ! xImage ) 1292 return nil; 1293 1294 Size aSize( rImage.GetSizePixel() ); 1295 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )]; 1296 if( pImage ) 1297 { 1298 [pImage setFlipped: YES]; 1299 [pImage lockFocus]; 1300 1301 NSGraphicsContext* pContext = [NSGraphicsContext currentContext]; 1302 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]); 1303 1304 const CGRect aDstRect = CGRectMake( 0, 0, aSize.Width(), aSize.Height()); 1305 CGContextDrawImage( rCGContext, aDstRect, xImage ); 1306 1307 [pImage unlockFocus]; 1308 } 1309 1310 CGImageRelease( xImage ); 1311 1312 return pImage; 1313 } 1314