Update ooo320-m1
[ooovba.git] / vcl / aqua / source / app / salinst.cxx
blob851dabb54525de60dd939bb1ad4e53a8110fce37
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salinst.cxx,v $
10 * $Revision: 1.53.22.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <stdio.h>
36 #include "tools/fsys.hxx"
37 #include "tools/getprocessworkingdir.hxx"
38 #include "osl/process.h"
39 #include "rtl/ustrbuf.hxx"
40 #include "vcl/svapp.hxx"
41 #include "vcl/print.h"
42 #include "vcl/salimestatus.hxx"
43 #include "vcl/window.hxx"
44 #include "vcl/timer.hxx"
45 #include "vcl/impbmp.hxx"
47 #include "saldata.hxx"
48 #include "salinst.h"
49 #include "salframe.h"
50 #include "salobj.h"
51 #include "salsys.h"
52 #include "salvd.h"
53 #include "salbmp.h"
54 #include "salprn.h"
55 #include "saltimer.h"
56 #include "vclnsapp.h"
58 #include <comphelper/processfactory.hxx>
60 #include <com/sun/star/beans/XPropertySet.hpp>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
63 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
66 #include "premac.h"
67 #include <Foundation/Foundation.h>
68 #include <ApplicationServices/ApplicationServices.h>
69 #import "apple_remote/RemoteMainController.h"
70 #include "apple_remote/RemoteControl.h"
71 #include "postmac.h"
74 using namespace std;
75 using namespace ::com::sun::star;
77 extern BOOL ImplSVMain();
79 static BOOL* gpbInit = 0;
80 static NSMenu* pDockMenu = nil;
81 static bool bNoSVMain = true;
82 static bool bLeftMain = false;
83 // -----------------------------------------------------------------------
85 class AquaDelayedSettingsChanged : public Timer
87 bool mbInvalidate;
88 public:
89 AquaDelayedSettingsChanged( bool bInvalidate ) :
90 mbInvalidate( bInvalidate )
94 virtual void Timeout()
96 SalData* pSalData = GetSalData();
97 if( ! pSalData->maFrames.empty() )
98 pSalData->maFrames.front()->CallCallback( SALEVENT_SETTINGSCHANGED, NULL );
100 if( mbInvalidate )
102 for( std::list< AquaSalFrame* >::iterator it = pSalData->maFrames.begin();
103 it != pSalData->maFrames.end(); ++it )
105 if( (*it)->mbShown )
106 (*it)->SendPaintEvent( NULL );
109 Stop();
110 delete this;
114 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate )
116 vos::OGuard aGuard( *mpSalYieldMutex );
117 AquaDelayedSettingsChanged* pTimer = new AquaDelayedSettingsChanged( bInvalidate );
118 pTimer->SetTimeout( 50 );
119 pTimer->Start();
123 // the AppEventList must be available before any SalData/SalInst/etc. objects are ready
124 typedef std::list<const ApplicationEvent*> AppEventList;
125 AppEventList AquaSalInstance::aAppEventList;
127 NSMenu* AquaSalInstance::GetDynamicDockMenu()
129 if( ! pDockMenu && ! bLeftMain )
130 pDockMenu = [[NSMenu alloc] initWithTitle: @""];
131 return pDockMenu;
134 bool AquaSalInstance::isOnCommandLine( const rtl::OUString& rArg )
136 sal_uInt32 nArgs = osl_getCommandArgCount();
137 for( sal_uInt32 i = 0; i < nArgs; i++ )
139 rtl::OUString aArg;
140 osl_getCommandArg( i, &aArg.pData );
141 if( aArg.equals( rArg ) )
142 return true;
144 return false;
148 // initialize the cocoa VCL_NSApplication object
149 // returns an NSAutoreleasePool that must be released when the event loop begins
150 static void initNSApp()
152 // create our cocoa NSApplication
153 [VCL_NSApplication sharedApplication];
155 SalData::ensureThreadAutoreleasePool();
157 // put cocoa into multithreaded mode
158 [NSThread detachNewThreadSelector:@selector(enableCocoaThreads:) toTarget:[[CocoaThreadEnabler alloc] init] withObject:nil];
160 // activate our delegate methods
161 [NSApp setDelegate: NSApp];
163 [[NSNotificationCenter defaultCenter] addObserver: NSApp
164 selector: @selector(systemColorsChanged:)
165 name: NSSystemColorsDidChangeNotification
166 object: nil ];
167 [[NSNotificationCenter defaultCenter] addObserver: NSApp
168 selector: @selector(screenParametersChanged:)
169 name: NSApplicationDidChangeScreenParametersNotification
170 object: nil ];
171 // add observers for some settings changes that affect vcl's settings
172 // scrollbar variant
173 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
174 selector: @selector(scrollbarVariantChanged:)
175 name: @"AppleAquaScrollBarVariantChanged"
176 object: nil ];
177 // scrollbar page behavior ("jump to here" or not)
178 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
179 selector: @selector(scrollbarSettingsChanged:)
180 name: @"AppleNoRedisplayAppearancePreferenceChanged"
181 object: nil ];
183 // get System Version and store the value in GetSalData()->mnSystemVersion
184 OSErr err = noErr;
185 SInt32 systemVersion = VER_TIGER; // Initialize with minimal requirement
186 if( (err = Gestalt(gestaltSystemVersion, &systemVersion)) == noErr )
188 GetSalData()->mnSystemVersion = systemVersion;
189 #if OSL_DEBUG_LEVEL > 1
190 fprintf( stderr, "System Version %x\n", (unsigned int)systemVersion);
191 #endif
193 else
194 NSLog(@"Unable to obtain system version: %ld", (long)err);
196 // Initialize Apple Remote
197 GetSalData()->mpMainController = [[MainController alloc] init];
199 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
200 selector: @selector(applicationWillBecomeActive:)
201 name: @"AppleRemoteWillBecomeActive"
202 object: nil ];
204 [[NSDistributedNotificationCenter defaultCenter] addObserver: NSApp
205 selector: @selector(applicationWillResignActive:)
206 name: @"AppleRemoteWillResignActive"
207 object: nil ];
209 if( ImplGetSVData()->mbIsTestTool )
210 [NSApp activateIgnoringOtherApps: YES];
213 BOOL ImplSVMainHook( BOOL * pbInit )
215 gpbInit = pbInit;
217 bNoSVMain = false;
218 initNSApp();
220 NSPoint aPt = { 0, 0 };
221 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
222 location: aPt
223 modifierFlags: 0
224 timestamp: 0
225 windowNumber: 0
226 context: nil
227 subtype: AquaSalInstance::AppExecuteSVMain
228 data1: 0
229 data2: 0 ];
230 if( pEvent )
232 [NSApp postEvent: pEvent atStart: NO];
234 rtl::OUString aExeURL, aExe;
235 osl_getExecutableFile( &aExeURL.pData );
236 osl_getSystemPathFromFileURL( aExeURL.pData, &aExe.pData );
237 rtl::OString aByteExe( rtl::OUStringToOString( aExe, osl_getThreadTextEncoding() ) );
239 #ifdef DEBUG
240 aByteExe += OString ( " NSAccessibilityDebugLogLevel 1" );
241 const char* pArgv[] = { aByteExe.getStr(), NULL };
242 NSApplicationMain( 3, pArgv );
243 #else
244 const char* pArgv[] = { aByteExe.getStr(), NULL };
245 NSApplicationMain( 1, pArgv );
246 #endif
248 else
250 DBG_ERROR( "NSApplication initialization could not be done" );
253 return TRUE; // indicate that ImplSVMainHook is implemented
256 // =======================================================================
258 void SalAbort( const XubString& rErrorText )
260 if( !rErrorText.Len() )
261 fprintf( stderr, "Application Error " );
262 else
263 fprintf( stderr, "%s ",
264 ByteString( rErrorText, gsl_getSystemTextEncoding() ).GetBuffer() );
265 abort();
268 // -----------------------------------------------------------------------
270 void InitSalData()
272 SalData *pSalData = new SalData;
273 SetSalData( pSalData );
276 // -----------------------------------------------------------------------
278 const ::rtl::OUString& SalGetDesktopEnvironment()
280 static OUString aDesktopEnvironment(RTL_CONSTASCII_USTRINGPARAM( "MacOSX" ));
281 return aDesktopEnvironment;
284 // -----------------------------------------------------------------------
286 void DeInitSalData()
288 SalData *pSalData = GetSalData();
289 if( pSalData->mpStatusItem )
291 [pSalData->mpStatusItem release];
292 pSalData->mpStatusItem = nil;
294 delete pSalData;
295 SetSalData( NULL );
298 // -----------------------------------------------------------------------
300 extern "C" {
301 #include <crt_externs.h>
304 // -----------------------------------------------------------------------
306 void InitSalMain()
308 rtl::OUString urlWorkDir;
309 rtl_uString *sysWorkDir = NULL;
310 if (tools::getProcessWorkingDir(&urlWorkDir))
312 oslFileError err2 = osl_getSystemPathFromFileURL(urlWorkDir.pData, &sysWorkDir);
313 if (err2 == osl_File_E_None)
315 ByteString aPath( getenv( "PATH" ) );
316 ByteString aResPath( getenv( "STAR_RESOURCEPATH" ) );
317 ByteString aLibPath( getenv( "DYLD_LIBRARY_PATH" ) );
318 ByteString aCmdPath( OUStringToOString(OUString(sysWorkDir), RTL_TEXTENCODING_UTF8).getStr() );
319 ByteString aTmpPath;
320 // Get absolute path of command's directory
321 if ( aCmdPath.Len() ) {
322 DirEntry aCmdDirEntry( aCmdPath );
323 aCmdDirEntry.ToAbs();
324 aCmdPath = ByteString( aCmdDirEntry.GetPath().GetFull(), RTL_TEXTENCODING_ASCII_US );
326 // Assign to PATH environment variable
327 if ( aCmdPath.Len() )
329 aTmpPath = ByteString( "PATH=" );
330 aTmpPath += aCmdPath;
331 if ( aPath.Len() )
332 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
333 aTmpPath += aPath;
334 putenv( (char*)aTmpPath.GetBuffer() );
336 // Assign to STAR_RESOURCEPATH environment variable
337 if ( aCmdPath.Len() )
339 aTmpPath = ByteString( "STAR_RESOURCEPATH=" );
340 aTmpPath += aCmdPath;
341 if ( aResPath.Len() )
342 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
343 aTmpPath += aResPath;
344 putenv( (char*)aTmpPath.GetBuffer() );
346 // Assign to DYLD_LIBRARY_PATH environment variable
347 if ( aCmdPath.Len() )
349 aTmpPath = ByteString( "DYLD_LIBRARY_PATH=" );
350 aTmpPath += aCmdPath;
351 if ( aLibPath.Len() )
352 aTmpPath += ByteString( DirEntry::GetSearchDelimiter(), RTL_TEXTENCODING_ASCII_US );
353 aTmpPath += aLibPath;
354 putenv( (char*)aTmpPath.GetBuffer() );
360 // -----------------------------------------------------------------------
362 void DeInitSalMain()
366 // =======================================================================
368 SalYieldMutex::SalYieldMutex()
370 mnCount = 0;
371 mnThreadId = 0;
374 void SalYieldMutex::acquire()
376 OMutex::acquire();
377 mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
378 mnCount++;
381 void SalYieldMutex::release()
383 if ( mnThreadId == NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
385 if ( mnCount == 1 )
386 mnThreadId = 0;
387 mnCount--;
389 OMutex::release();
392 sal_Bool SalYieldMutex::tryToAcquire()
394 if ( OMutex::tryToAcquire() )
396 mnThreadId = NAMESPACE_VOS(OThread)::getCurrentIdentifier();
397 mnCount++;
398 return sal_True;
400 else
401 return sal_False;
404 // -----------------------------------------------------------------------
406 // some convenience functions regarding the yield mutex, aka solar mutex
408 BOOL ImplSalYieldMutexTryToAcquire()
410 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
411 if ( pInst )
412 return pInst->mpSalYieldMutex->tryToAcquire();
413 else
414 return FALSE;
417 void ImplSalYieldMutexAcquire()
419 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
420 if ( pInst )
421 pInst->mpSalYieldMutex->acquire();
424 void ImplSalYieldMutexRelease()
426 AquaSalInstance* pInst = (AquaSalInstance*) GetSalData()->mpFirstInstance;
427 if ( pInst )
428 pInst->mpSalYieldMutex->release();
431 // =======================================================================
433 SalInstance* CreateSalInstance()
435 // this is the case for not using SVMain
436 // not so good
437 if( bNoSVMain )
438 initNSApp();
440 SalData* pSalData = GetSalData();
441 DBG_ASSERT( pSalData->mpFirstInstance == NULL, "more than one instance created" );
442 AquaSalInstance* pInst = new AquaSalInstance;
444 // init instance (only one instance in this version !!!)
445 pSalData->mpFirstInstance = pInst;
446 // this one is for outside AquaSalInstance::Yield
447 SalData::ensureThreadAutoreleasePool();
448 // no focus rects on NWF aqua
449 ImplGetSVData()->maNWFData.mbNoFocusRects = true;
450 ImplGetSVData()->maNWFData.mbNoBoldTabFocus = true;
451 ImplGetSVData()->maNWFData.mbNoActiveTabTextRaise = true;
452 ImplGetSVData()->maNWFData.mbCenteredTabs = true;
453 ImplGetSVData()->maNWFData.mbProgressNeedsErase = true;
454 ImplGetSVData()->maNWFData.mbCheckBoxNeedsErase = true;
455 ImplGetSVData()->maGDIData.mbPrinterPullModel = true;
456 ImplGetSVData()->maGDIData.mbNoXORClipping = true;
457 ImplGetSVData()->maWinData.mbNoSaveBackground = true;
459 return pInst;
462 // -----------------------------------------------------------------------
464 void DestroySalInstance( SalInstance* pInst )
466 delete pInst;
469 // -----------------------------------------------------------------------
471 AquaSalInstance::AquaSalInstance()
473 mpSalYieldMutex = new SalYieldMutex;
474 mpSalYieldMutex->acquire();
475 maMainThread = vos::OThread::getCurrentIdentifier();
476 mbWaitingYield = false;
477 maUserEventListMutex = osl_createMutex();
478 mnActivePrintJobs = 0;
481 // -----------------------------------------------------------------------
483 AquaSalInstance::~AquaSalInstance()
485 mpSalYieldMutex->release();
486 delete mpSalYieldMutex;
487 osl_destroyMutex( maUserEventListMutex );
490 // -----------------------------------------------------------------------
492 void AquaSalInstance::wakeupYield()
494 // wakeup :Yield
495 if( mbWaitingYield )
497 SalData::ensureThreadAutoreleasePool();
498 NSPoint aPt = { 0, 0 };
499 NSEvent* pEvent = [NSEvent otherEventWithType: NSApplicationDefined
500 location: aPt
501 modifierFlags: 0
502 timestamp: 0
503 windowNumber: 0
504 context: nil
505 subtype: AquaSalInstance::YieldWakeupEvent
506 data1: 0
507 data2: 0 ];
508 if( pEvent )
509 [NSApp postEvent: pEvent atStart: NO];
513 // -----------------------------------------------------------------------
515 void AquaSalInstance::PostUserEvent( AquaSalFrame* pFrame, USHORT nType, void* pData )
517 osl_acquireMutex( maUserEventListMutex );
518 maUserEvents.push_back( SalUserEvent( pFrame, pData, nType ) );
519 osl_releaseMutex( maUserEventListMutex );
521 // notify main loop that an event has arrived
522 wakeupYield();
525 // -----------------------------------------------------------------------
527 vos::IMutex* AquaSalInstance::GetYieldMutex()
529 return mpSalYieldMutex;
532 // -----------------------------------------------------------------------
534 ULONG AquaSalInstance::ReleaseYieldMutex()
536 SalYieldMutex* pYieldMutex = mpSalYieldMutex;
537 if ( pYieldMutex->GetThreadId() ==
538 NAMESPACE_VOS(OThread)::getCurrentIdentifier() )
540 ULONG nCount = pYieldMutex->GetAcquireCount();
541 ULONG n = nCount;
542 while ( n )
544 pYieldMutex->release();
545 n--;
548 return nCount;
550 else
551 return 0;
554 // -----------------------------------------------------------------------
556 void AquaSalInstance::AcquireYieldMutex( ULONG nCount )
558 SalYieldMutex* pYieldMutex = mpSalYieldMutex;
559 while ( nCount )
561 pYieldMutex->acquire();
562 nCount--;
566 // -----------------------------------------------------------------------
568 bool AquaSalInstance::isNSAppThread() const
570 return vos::OThread::getCurrentIdentifier() == maMainThread;
573 // -----------------------------------------------------------------------
575 void AquaSalInstance::handleAppDefinedEvent( NSEvent* pEvent )
577 switch( [pEvent subtype] )
579 case AppStartTimerEvent:
580 AquaSalTimer::handleStartTimerEvent( pEvent );
581 break;
582 case AppEndLoopEvent:
583 [NSApp stop: NSApp];
584 break;
585 case AppExecuteSVMain:
587 BOOL bResult = ImplSVMain();
588 if( gpbInit )
589 *gpbInit = bResult;
590 [NSApp stop: NSApp];
591 bLeftMain = true;
592 if( pDockMenu )
594 [pDockMenu release];
595 pDockMenu = nil;
598 break;
599 case AppleRemoteEvent:
601 sal_Int16 nCommand = 0;
602 SalData* pSalData = GetSalData();
603 bool bIsFullScreenMode = false;
605 std::list<AquaSalFrame*>::iterator it = pSalData->maFrames.begin();
606 while( (*it) && ( (it != pSalData->maFrames.end() ) || ( (*it)->mbFullScreen == false ) ) )
608 if ( ((*it)->mbFullScreen == true) )
609 bIsFullScreenMode = true;
610 it++;
613 switch ([pEvent data1])
615 case kRemoteButtonPlay:
616 nCommand = ( bIsFullScreenMode == true ) ? MEDIA_COMMAND_PLAY_PAUSE : MEDIA_COMMAND_PLAY;
617 break;
619 // kept for experimentation purpose (scheduled for future implementation)
620 // case kRemoteButtonMenu: nCommand = MEDIA_COMMAND_MENU; break;
622 case kRemoteButtonPlus: nCommand = MEDIA_COMMAND_VOLUME_UP; break;
624 case kRemoteButtonMinus: nCommand = MEDIA_COMMAND_VOLUME_DOWN; break;
626 case kRemoteButtonRight: nCommand = MEDIA_COMMAND_NEXTTRACK; break;
628 case kRemoteButtonRight_Hold: nCommand = MEDIA_COMMAND_NEXTTRACK_HOLD; break;
630 case kRemoteButtonLeft: nCommand = MEDIA_COMMAND_PREVIOUSTRACK; break;
632 case kRemoteButtonLeft_Hold: nCommand = MEDIA_COMMAND_REWIND; break;
634 case kRemoteButtonPlay_Hold: nCommand = MEDIA_COMMAND_PLAY_HOLD; break;
636 case kRemoteButtonMenu_Hold: nCommand = MEDIA_COMMAND_STOP; break;
638 // FIXME : not detected
639 case kRemoteButtonPlus_Hold:
640 case kRemoteButtonMinus_Hold:
641 break;
643 default:
644 break;
646 AquaSalFrame* pFrame = pSalData->maFrames.front();
647 Window * pWindow = pFrame->GetWindow() ? pSalData->maFrames.front()->GetWindow() : NULL;
649 if( pWindow )
651 const Point aPoint;
652 CommandEvent aCEvt( aPoint, COMMAND_MEDIA, FALSE, &nCommand );
653 NotifyEvent aNCmdEvt( EVENT_COMMAND, pWindow, &aCEvt );
655 if ( !ImplCallPreNotify( aNCmdEvt ) )
656 pWindow->Command( aCEvt );
660 break;
662 case YieldWakeupEvent:
663 // do nothing, fall out of Yield
664 break;
666 default:
667 DBG_ERROR( "unhandled NSApplicationDefined event" );
668 break;
672 // -----------------------------------------------------------------------
674 class ReleasePoolHolder
676 NSAutoreleasePool* mpPool;
677 public:
678 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc] init] ) {}
679 ~ReleasePoolHolder() { [mpPool release]; }
682 void AquaSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
684 // ensure that the per thread autorelease pool is top level and
685 // will therefore not be destroyed by cocoa implicitly
686 SalData::ensureThreadAutoreleasePool();
688 // NSAutoreleasePool documentation suggests we should have
689 // an own pool for each yield level
690 ReleasePoolHolder aReleasePool;
692 // Release all locks so that we don't deadlock when we pull pending
693 // events from the event queue
694 bool bDispatchUser = true;
695 while( bDispatchUser )
697 ULONG nCount = ReleaseYieldMutex();
699 // get one user event
700 osl_acquireMutex( maUserEventListMutex );
701 SalUserEvent aEvent( NULL, NULL, 0 );
702 if( ! maUserEvents.empty() )
704 aEvent = maUserEvents.front();
705 maUserEvents.pop_front();
707 else
708 bDispatchUser = false;
709 osl_releaseMutex( maUserEventListMutex );
711 AcquireYieldMutex( nCount );
713 // dispatch it
714 if( aEvent.mpFrame && AquaSalFrame::isAlive( aEvent.mpFrame ) )
716 aEvent.mpFrame->CallCallback( aEvent.mnType, aEvent.mpData );
717 // return if only one event is asked for
718 if( ! bHandleAllCurrentEvents )
719 return;
723 // handle cocoa event queue
724 // cocoa events mye be only handled in the thread the NSApp was created
725 if( isNSAppThread() && mnActivePrintJobs == 0 )
727 // we need to be woken up by a cocoa-event
728 // if a user event should be posted by the event handling below
729 bool bOldWaitingYield = mbWaitingYield;
730 mbWaitingYield = bWait;
732 // handle available events
733 NSEvent* pEvent = nil;
734 bool bHadEvent = false;
737 ULONG nCount = ReleaseYieldMutex();
739 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
740 inMode: NSDefaultRunLoopMode dequeue: YES];
741 if( pEvent )
743 [NSApp sendEvent: pEvent];
744 bHadEvent = true;
746 [NSApp updateWindows];
748 AcquireYieldMutex( nCount );
749 } while( bHandleAllCurrentEvents && pEvent );
751 // if we had no event yet, wait for one if requested
752 if( bWait && ! bHadEvent )
754 ULONG nCount = ReleaseYieldMutex();
756 NSDate* pDt = AquaSalTimer::pRunningTimer ? [AquaSalTimer::pRunningTimer fireDate] : [NSDate distantFuture];
757 pEvent = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: pDt
758 inMode: NSDefaultRunLoopMode dequeue: YES];
759 if( pEvent )
760 [NSApp sendEvent: pEvent];
761 [NSApp updateWindows];
763 AcquireYieldMutex( nCount );
765 // #i86581#
766 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
767 // fixes the problem even seems to set the correct next firing date
768 // Why oh why ?
769 if( ! pEvent && AquaSalTimer::pRunningTimer )
771 // this cause crashes on MacOSX 10.4
772 // [AquaSalTimer::pRunningTimer fire];
773 ImplGetSVData()->mpSalTimer->CallCallback();
777 mbWaitingYield = bOldWaitingYield;
779 // collect update rectangles
780 const std::list< AquaSalFrame* > rFrames( GetSalData()->maFrames );
781 for( std::list< AquaSalFrame* >::const_iterator it = rFrames.begin(); it != rFrames.end(); ++it )
783 if( (*it)->mbShown && ! (*it)->maInvalidRect.IsEmpty() )
785 (*it)->Flush( (*it)->maInvalidRect );
786 (*it)->maInvalidRect.SetEmpty();
791 // we get some apple events way too early
792 // before the application is ready to handle them,
793 // so their corresponding application events need to be delayed
794 // now is a good time to handle at least one of them
795 if( bWait && !aAppEventList.empty() && ImplGetSVData()->maAppData.mbInAppExecute )
797 // make sure that only one application event is active at a time
798 static bool bInAppEvent = false;
799 if( !bInAppEvent )
801 bInAppEvent = true;
802 // get the next delayed application event
803 const ApplicationEvent* pAppEvent = aAppEventList.front();
804 aAppEventList.pop_front();
805 // handle one application event (no recursion)
806 const ImplSVData* pSVData = ImplGetSVData();
807 pSVData->mpApp->AppEvent( *pAppEvent );
808 delete pAppEvent;
809 // allow the next delayed application event
810 bInAppEvent = false;
815 // -----------------------------------------------------------------------
817 bool AquaSalInstance::AnyInput( USHORT nType )
819 if( nType & INPUT_APPEVENT )
821 if( ! aAppEventList.empty() )
822 return true;
823 if( nType == INPUT_APPEVENT )
824 return false;
827 if( nType & INPUT_TIMER )
829 if( AquaSalTimer::pRunningTimer )
831 NSDate* pDt = [AquaSalTimer::pRunningTimer fireDate];
832 if( pDt && [pDt timeIntervalSinceNow] < 0 )
834 return true;
839 unsigned/*NSUInteger*/ nEventMask = 0;
840 if( nType & INPUT_MOUSE)
841 nEventMask |=
842 NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask |
843 NSLeftMouseUpMask | NSRightMouseUpMask | NSOtherMouseUpMask |
844 NSLeftMouseDraggedMask | NSRightMouseDraggedMask | NSOtherMouseDraggedMask |
845 NSScrollWheelMask |
846 // NSMouseMovedMask |
847 NSMouseEnteredMask | NSMouseExitedMask;
848 if( nType & INPUT_KEYBOARD)
849 nEventMask |= NSKeyDownMask | NSKeyUpMask | NSFlagsChangedMask;
850 if( nType & INPUT_OTHER)
851 nEventMask |= NSTabletPoint;
852 // TODO: INPUT_PAINT / more INPUT_OTHER
853 if( !nType)
854 return false;
856 NSEvent* pEvent = [NSApp nextEventMatchingMask: nEventMask untilDate: nil
857 inMode: NSDefaultRunLoopMode dequeue: NO];
858 return (pEvent != NULL);
861 // -----------------------------------------------------------------------
863 SalFrame* AquaSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, ULONG nSalFrameStyle )
865 return NULL;
868 // -----------------------------------------------------------------------
870 SalFrame* AquaSalInstance::CreateFrame( SalFrame* pParent, ULONG nSalFrameStyle )
872 SalData::ensureThreadAutoreleasePool();
874 SalFrame* pFrame = new AquaSalFrame( pParent, nSalFrameStyle );
875 return pFrame;
878 // -----------------------------------------------------------------------
880 void AquaSalInstance::DestroyFrame( SalFrame* pFrame )
882 delete pFrame;
885 // -----------------------------------------------------------------------
887 SalObject* AquaSalInstance::CreateObject( SalFrame* pParent, SystemWindowData* /* pWindowData */, BOOL /* bShow */ )
889 // SystemWindowData is meaningless on Mac OS X
890 AquaSalObject *pObject = NULL;
892 if ( pParent )
893 pObject = new AquaSalObject( static_cast<AquaSalFrame*>(pParent) );
895 return pObject;
898 // -----------------------------------------------------------------------
900 void AquaSalInstance::DestroyObject( SalObject* pObject )
902 delete ( pObject );
905 // -----------------------------------------------------------------------
907 SalPrinter* AquaSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
909 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter*>(pInfoPrinter) );
912 // -----------------------------------------------------------------------
914 void AquaSalInstance::DestroyPrinter( SalPrinter* pPrinter )
916 delete pPrinter;
919 // -----------------------------------------------------------------------
921 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
923 NSArray* pNames = [NSPrinter printerNames];
924 NSArray* pTypes = [NSPrinter printerTypes];
925 unsigned int nNameCount = pNames ? [pNames count] : 0;
926 unsigned int nTypeCount = pTypes ? [pTypes count] : 0;
927 DBG_ASSERT( nTypeCount == nNameCount, "type count not equal to printer count" );
928 for( unsigned int i = 0; i < nNameCount; i++ )
930 NSString* pName = [pNames objectAtIndex: i];
931 NSString* pType = i < nTypeCount ? [pTypes objectAtIndex: i] : nil;
932 if( pName )
934 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
935 pInfo->maPrinterName = GetOUString( pName );
936 if( pType )
937 pInfo->maDriver = GetOUString( pType );
938 pInfo->mnStatus = 0;
939 pInfo->mnJobs = 0;
940 pInfo->mpSysData = NULL;
942 pList->Add( pInfo );
947 // -----------------------------------------------------------------------
949 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* pInfo )
953 // -----------------------------------------------------------------------
955 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
957 delete pInfo;
960 // -----------------------------------------------------------------------
962 XubString AquaSalInstance::GetDefaultPrinter()
964 if( ! maDefaultPrinter.getLength() )
966 NSPrintInfo* pPI = [NSPrintInfo sharedPrintInfo];
967 DBG_ASSERT( pPI, "no print info" );
968 if( pPI )
970 NSPrinter* pPr = [pPI printer];
971 DBG_ASSERT( pPr, "no printer in default info" );
972 if( pPr )
974 NSString* pDefName = [pPr name];
975 DBG_ASSERT( pDefName, "printer has no name" );
976 maDefaultPrinter = GetOUString( pDefName );
980 return maDefaultPrinter;
983 // -----------------------------------------------------------------------
985 SalInfoPrinter* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
986 ImplJobSetup* pSetupData )
988 SalInfoPrinter* pNewInfoPrinter = NULL;
989 if( pQueueInfo )
991 pNewInfoPrinter = new AquaSalInfoPrinter( *pQueueInfo );
992 if( pSetupData )
993 pNewInfoPrinter->SetPrinterData( pSetupData );
996 return pNewInfoPrinter;
999 // -----------------------------------------------------------------------
1001 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
1003 delete pPrinter;
1006 // -----------------------------------------------------------------------
1008 SalSystem* AquaSalInstance::CreateSystem()
1010 return new AquaSalSystem();
1013 // -----------------------------------------------------------------------
1015 void AquaSalInstance::DestroySystem( SalSystem* pSystem )
1017 delete pSystem;
1020 // -----------------------------------------------------------------------
1022 void AquaSalInstance::SetEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
1026 // -----------------------------------------------------------------------
1028 void AquaSalInstance::SetErrorEventCallback( void* pInstance, bool(*pCallback)(void*,void*,int) )
1032 // -----------------------------------------------------------------------
1034 void* AquaSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
1036 rReturnedBytes = 1;
1037 rReturnedType = AsciiCString;
1038 return (void*)"";
1041 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
1042 // to UTF-8 before encoding non ascii characters, which is not what other apps expect.
1043 static rtl::OUString translateToExternalUrl(const rtl::OUString& internalUrl)
1045 rtl::OUString extUrl;
1047 uno::Reference< lang::XMultiServiceFactory > sm = comphelper::getProcessServiceFactory();
1048 if (sm.is())
1050 uno::Reference< beans::XPropertySet > pset;
1051 sm->queryInterface( getCppuType( &pset )) >>= pset;
1052 if (pset.is())
1054 uno::Reference< uno::XComponentContext > context;
1055 static const rtl::OUString DEFAULT_CONTEXT( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) );
1056 pset->getPropertyValue(DEFAULT_CONTEXT) >>= context;
1057 if (context.is())
1058 extUrl = uri::ExternalUriReferenceTranslator::create(context)->translateToExternal(internalUrl);
1061 return extUrl;
1064 // #i104525# many versions of OSX have problems with some URLs:
1065 // when an app requests OSX to add one of these URLs to the "Recent Items" list
1066 // then this app gets killed (TextEdit, Preview, etc. and also OOo)
1067 static bool isDangerousUrl( const rtl::OUString& rUrl )
1069 // use a heuristic that detects all known cases since there is no official comment
1070 // on the exact impact and root cause of the OSX bug
1071 const int nLen = rUrl.getLength();
1072 const sal_Unicode* p = rUrl.getStr();
1073 for( int i = 0; i < nLen-3; ++i, ++p ) {
1074 if( p[0] != '%' )
1075 continue;
1076 // escaped percent?
1077 if( (p[1] == '2') && (p[2] == '5') )
1078 return true;
1079 // escapes are considered to be UTF-8 encoded
1080 // => check for invalid UTF-8 leading byte
1081 if( (p[1] != 'f') && (p[1] != 'F') )
1082 continue;
1083 int cLowNibble = p[2];
1084 if( (cLowNibble >= '0' ) && (cLowNibble <= '9'))
1085 return false;
1086 if( cLowNibble >= 'a' )
1087 cLowNibble -= 'a' - 'A';
1088 if( (cLowNibble < 'A') || (cLowNibble >= 'C'))
1089 return true;
1092 return false;
1095 void AquaSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
1097 // Convert file URL for external use (see above)
1098 rtl::OUString externalUrl = translateToExternalUrl(rFileUrl);
1099 if( 0 == externalUrl.getLength() )
1100 externalUrl = rFileUrl;
1102 if( externalUrl.getLength() && !isDangerousUrl( externalUrl ) )
1104 NSString* pString = CreateNSString( externalUrl );
1105 NSURL* pURL = [NSURL URLWithString: pString];
1107 if( pURL )
1109 NSDocumentController* pCtrl = [NSDocumentController sharedDocumentController];
1110 [pCtrl noteNewRecentDocumentURL: pURL];
1112 if( pString )
1113 [pString release];
1118 // -----------------------------------------------------------------------
1120 SalTimer* AquaSalInstance::CreateSalTimer()
1122 return new AquaSalTimer();
1125 // -----------------------------------------------------------------------
1127 SalSystem* AquaSalInstance::CreateSalSystem()
1129 return new AquaSalSystem();
1132 // -----------------------------------------------------------------------
1134 SalBitmap* AquaSalInstance::CreateSalBitmap()
1136 return new AquaSalBitmap();
1139 // -----------------------------------------------------------------------
1141 SalSession* AquaSalInstance::CreateSalSession()
1143 return NULL;
1146 // -----------------------------------------------------------------------
1148 class MacImeStatus : public SalI18NImeStatus
1150 public:
1151 MacImeStatus() {}
1152 virtual ~MacImeStatus() {}
1154 // asks whether there is a status window available
1155 // to toggle into menubar
1156 virtual bool canToggle() { return false; }
1157 virtual void toggle() {}
1160 // -----------------------------------------------------------------------
1162 SalI18NImeStatus* AquaSalInstance::CreateI18NImeStatus()
1164 return new MacImeStatus();
1167 // YieldMutexReleaser
1168 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
1170 SalData* pSalData = GetSalData();
1171 if( ! pSalData->mpFirstInstance->isNSAppThread() )
1173 SalData::ensureThreadAutoreleasePool();
1174 mnCount = pSalData->mpFirstInstance->ReleaseYieldMutex();
1178 YieldMutexReleaser::~YieldMutexReleaser()
1180 if( mnCount != 0 )
1181 GetSalData()->mpFirstInstance->AcquireYieldMutex( mnCount );
1184 //////////////////////////////////////////////////////////////
1185 rtl::OUString GetOUString( CFStringRef rStr )
1187 if( rStr == 0 )
1188 return rtl::OUString();
1189 CFIndex nLength = CFStringGetLength( rStr );
1190 if( nLength == 0 )
1191 return rtl::OUString();
1192 const UniChar* pConstStr = CFStringGetCharactersPtr( rStr );
1193 if( pConstStr )
1194 return rtl::OUString( pConstStr, nLength );
1195 UniChar* pStr = reinterpret_cast<UniChar*>( rtl_allocateMemory( sizeof(UniChar)*nLength ) );
1196 CFRange aRange = { 0, nLength };
1197 CFStringGetCharacters( rStr, aRange, pStr );
1198 rtl::OUString aRet( pStr, nLength );
1199 rtl_freeMemory( pStr );
1200 return aRet;
1203 rtl::OUString GetOUString( NSString* pStr )
1205 if( ! pStr )
1206 return rtl::OUString();
1207 int nLen = [pStr length];
1208 if( nLen == 0 )
1209 return rtl::OUString();
1211 rtl::OUStringBuffer aBuf( nLen+1 );
1212 aBuf.setLength( nLen );
1213 [pStr getCharacters: const_cast<sal_Unicode*>(aBuf.getStr())];
1214 return aBuf.makeStringAndClear();
1217 CFStringRef CreateCFString( const rtl::OUString& rStr )
1219 return CFStringCreateWithCharacters(kCFAllocatorDefault, rStr.getStr(), rStr.getLength() );
1222 NSString* CreateNSString( const rtl::OUString& rStr )
1224 return [[NSString alloc] initWithCharacters: rStr.getStr() length: rStr.getLength()];
1227 CGImageRef CreateCGImage( const Image& rImage )
1229 BitmapEx aBmpEx( rImage.GetBitmapEx() );
1230 Bitmap aBmp( aBmpEx.GetBitmap() );
1232 if( ! aBmp || ! aBmp.ImplGetImpBitmap() )
1233 return NULL;
1235 // simple case, no transparency
1236 AquaSalBitmap* pSalBmp = static_cast<AquaSalBitmap*>(aBmp.ImplGetImpBitmap()->ImplGetSalBitmap());
1238 if( ! pSalBmp )
1239 return NULL;
1241 CGImageRef xImage = NULL;
1242 if( ! (aBmpEx.IsAlpha() || aBmpEx.IsTransparent() ) )
1243 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1244 else if( aBmpEx.IsAlpha() )
1246 AlphaMask aAlphaMask( aBmpEx.GetAlpha() );
1247 Bitmap aMask( aAlphaMask.GetBitmap() );
1248 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1249 if( pMaskBmp )
1250 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1251 else
1252 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1254 else if( aBmpEx.GetTransparentType() == TRANSPARENT_BITMAP )
1256 Bitmap aMask( aBmpEx.GetMask() );
1257 AquaSalBitmap* pMaskBmp = static_cast<AquaSalBitmap*>(aMask.ImplGetImpBitmap()->ImplGetSalBitmap());
1258 if( pMaskBmp )
1259 xImage = pSalBmp->CreateWithMask( *pMaskBmp, 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1260 else
1261 xImage = pSalBmp->CreateCroppedImage( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight );
1263 else if( aBmpEx.GetTransparentType() == TRANSPARENT_COLOR )
1265 Color aTransColor( aBmpEx.GetTransparentColor() );
1266 SalColor nTransColor = MAKE_SALCOLOR( aTransColor.GetRed(), aTransColor.GetGreen(), aTransColor.GetBlue() );
1267 xImage = pSalBmp->CreateColorMask( 0, 0, pSalBmp->mnWidth, pSalBmp->mnHeight, nTransColor );
1270 return xImage;
1273 NSImage* CreateNSImage( const Image& rImage )
1275 CGImageRef xImage = CreateCGImage( rImage );
1277 if( ! xImage )
1278 return nil;
1280 Size aSize( rImage.GetSizePixel() );
1281 NSImage* pImage = [[NSImage alloc] initWithSize: NSMakeSize( aSize.Width(), aSize.Height() )];
1282 if( pImage )
1284 [pImage setFlipped: YES];
1285 [pImage lockFocus];
1287 NSGraphicsContext* pContext = [NSGraphicsContext currentContext];
1288 CGContextRef rCGContext = reinterpret_cast<CGContextRef>([pContext graphicsPort]);
1290 const CGRect aDstRect = { {0, 0}, { aSize.Width(), aSize.Height() } };
1291 CGContextDrawImage( rCGContext, aDstRect, xImage );
1293 [pImage unlockFocus];
1296 CGImageRelease( xImage );
1298 return pImage;