1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
24 #include <comphelper/solarmutex.hxx>
26 #include "comphelper/lok.hxx"
28 #include "osl/process.h"
30 #include "rtl/ustrbuf.hxx"
32 #include <vcl/svapp.hxx>
33 #include <vcl/window.hxx>
34 #include <vcl/idle.hxx>
35 #include <vcl/svmain.hxx>
36 #include <vcl/opengl/OpenGLContext.hxx>
38 #include "osx/saldata.hxx"
39 #include "osx/salinst.h"
40 #include "osx/salframe.h"
41 #include "osx/salobj.h"
42 #include "osx/salsys.h"
43 #include "quartz/salvd.h"
44 #include "quartz/salbmp.h"
45 #include "quartz/utils.h"
46 #include "osx/salprn.h"
47 #include "osx/saltimer.h"
48 #include "osx/vclnsapp.h"
52 #include "salimestatus.hxx"
54 #include <comphelper/processfactory.hxx>
56 #include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
57 #include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
58 #include <com/sun/star/uno/XComponentContext.hpp>
61 #include <Foundation/Foundation.h>
62 #include <ApplicationServices/ApplicationServices.h>
63 #import "apple_remote/RemoteMainController.h"
64 #include "apple_remote/RemoteControl.h"
68 #include <crt_externs.h>
72 using namespace ::com::sun::star
;
74 static int* gpnInit
= nullptr;
75 static NSMenu
* pDockMenu
= nil
;
76 static bool bNoSVMain
= true;
77 static bool bLeftMain
= false;
79 class AquaDelayedSettingsChanged
: public Idle
83 AquaDelayedSettingsChanged( bool bInvalidate
) :
84 mbInvalidate( bInvalidate
)
88 virtual void Invoke() override
90 SalData
* pSalData
= GetSalData();
91 if( ! pSalData
->maFrames
.empty() )
92 pSalData
->maFrames
.front()->CallCallback( SalEvent::SettingsChanged
, nullptr );
96 for( std::list
< AquaSalFrame
* >::iterator it
= pSalData
->maFrames
.begin();
97 it
!= pSalData
->maFrames
.end(); ++it
)
100 (*it
)->SendPaintEvent();
108 void AquaSalInstance::delayedSettingsChanged( bool bInvalidate
)
110 osl::Guard
< comphelper::SolarMutex
> aGuard( *mpSalYieldMutex
);
111 AquaDelayedSettingsChanged
* pIdle
= new AquaDelayedSettingsChanged( bInvalidate
);
112 pIdle
->SetPriority( TaskPriority::MEDIUM
);
116 // the std::list<const ApplicationEvent*> must be available before any SalData/SalInst/etc. objects are ready
117 std::list
<const ApplicationEvent
*> AquaSalInstance::aAppEventList
;
119 NSMenu
* AquaSalInstance::GetDynamicDockMenu()
121 if( ! pDockMenu
&& ! bLeftMain
)
122 pDockMenu
= [[NSMenu alloc
] initWithTitle
: @
""];
126 bool AquaSalInstance::isOnCommandLine( const OUString
& rArg
)
128 sal_uInt32 nArgs
= osl_getCommandArgCount();
129 for( sal_uInt32 i
= 0; i
< nArgs
; i
++ )
132 osl_getCommandArg( i
, &aArg
.pData
);
133 if( aArg
.equals( rArg
) )
139 // initialize the cocoa VCL_NSApplication object
140 // returns an NSAutoreleasePool that must be released when the event loop begins
141 static void initNSApp()
143 // create our cocoa NSApplication
144 [VCL_NSApplication sharedApplication
];
146 SalData::ensureThreadAutoreleasePool();
148 // put cocoa into multithreaded mode
149 [NSThread detachNewThreadSelector
:@
selector(enableCocoaThreads
:) toTarget
:[[CocoaThreadEnabler alloc
] init
] withObject
:nil
];
151 // activate our delegate methods
152 [NSApp setDelegate
: NSApp
];
154 [[NSNotificationCenter defaultCenter
] addObserver
: NSApp
155 selector
: @
selector(systemColorsChanged
:)
156 name
: NSSystemColorsDidChangeNotification
158 [[NSNotificationCenter defaultCenter
] addObserver
: NSApp
159 selector
: @
selector(screenParametersChanged
:)
160 name
: NSApplicationDidChangeScreenParametersNotification
162 // add observers for some settings changes that affect vcl's settings
164 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
165 selector
: @
selector(scrollbarVariantChanged
:)
166 name
: @
"AppleAquaScrollBarVariantChanged"
168 // scrollbar page behavior ("jump to here" or not)
169 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
170 selector
: @
selector(scrollbarSettingsChanged
:)
171 name
: @
"AppleNoRedisplayAppearancePreferenceChanged"
173 #if !HAVE_FEATURE_MACOSX_SANDBOX
174 // Initialize Apple Remote
175 GetSalData()->mpAppleRemoteMainController
= [[AppleRemoteMainController alloc
] init
];
177 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
178 selector
: @
selector(applicationWillBecomeActive
:)
179 name
: @
"AppleRemoteWillBecomeActive"
182 [[NSDistributedNotificationCenter defaultCenter
] addObserver
: NSApp
183 selector
: @
selector(applicationWillResignActive
:)
184 name
: @
"AppleRemoteWillResignActive"
189 bool ImplSVMainHook( int * pnInit
)
191 if (comphelper::LibreOfficeKit::isActive())
194 NSAutoreleasePool
* pool
= [ [ NSAutoreleasePool alloc
] init
];
195 unlink([[NSString stringWithFormat
:@
"%@/Library/Saved Application State/%s.savedState/restorecount.plist", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER
] UTF8String
]);
196 unlink([[NSString stringWithFormat
:@
"%@/Library/Saved Application State/%s.savedState/restorecount.txt", NSHomeDirectory(), MACOSX_BUNDLE_IDENTIFIER
] UTF8String
]);
204 OUString aExeURL
, aExe
;
205 osl_getExecutableFile( &aExeURL
.pData
);
206 osl_getSystemPathFromFileURL( aExeURL
.pData
, &aExe
.pData
);
207 OString
aByteExe( OUStringToOString( aExe
, osl_getThreadTextEncoding() ) );
210 aByteExe
+= OString ( " NSAccessibilityDebugLogLevel 1" );
211 const char* pArgv
[] = { aByteExe
.getStr(), NULL
};
212 NSApplicationMain( 3, pArgv
);
214 const char* pArgv
[] = { aByteExe
.getStr(), nullptr };
215 NSApplicationMain( 1, pArgv
);
218 return TRUE
; // indicate that ImplSVMainHook is implemented
221 void SalAbort( const OUString
& rErrorText
, bool bDumpCore
)
223 if( rErrorText
.isEmpty() )
224 fprintf( stderr
, "Application Error " );
226 fprintf( stderr
, "%s ",
227 OUStringToOString( rErrorText
, osl_getThreadTextEncoding() ).getStr() );
236 SalData
*pSalData
= new SalData
;
237 SetSalData( pSalData
);
240 const OUString
& SalGetDesktopEnvironment()
242 static OUString
aDesktopEnvironment( "MacOSX" );
243 return aDesktopEnvironment
;
248 SalData
*pSalData
= GetSalData();
249 if( pSalData
->mpStatusItem
)
251 [pSalData
->mpStatusItem release
];
252 pSalData
->mpStatusItem
= nil
;
255 SetSalData( nullptr );
262 SalYieldMutex::SalYieldMutex()
268 void SalYieldMutex::acquire()
271 mnThreadId
= osl::Thread::getCurrentIdentifier();
275 void SalYieldMutex::release()
277 if ( mnThreadId
== osl::Thread::getCurrentIdentifier() )
281 // TODO: add OpenGLContext::prepareForYield with vcl OpenGL support
289 bool SalYieldMutex::tryToAcquire()
291 if ( m_mutex
.tryToAcquire() )
293 mnThreadId
= osl::Thread::getCurrentIdentifier();
301 // some convenience functions regarding the yield mutex, aka solar mutex
303 bool ImplSalYieldMutexTryToAcquire()
305 AquaSalInstance
* pInst
= GetSalData()->mpFirstInstance
;
307 return pInst
->mpSalYieldMutex
->tryToAcquire();
312 void ImplSalYieldMutexRelease()
314 AquaSalInstance
* pInst
= GetSalData()->mpFirstInstance
;
316 pInst
->mpSalYieldMutex
->release();
319 SalInstance
* CreateSalInstance()
321 // this is the case for not using SVMain
326 SalData
* pSalData
= GetSalData();
327 SAL_WARN_IF( pSalData
->mpFirstInstance
!= nullptr, "vcl", "more than one instance created" );
328 AquaSalInstance
* pInst
= new AquaSalInstance
;
330 // init instance (only one instance in this version !!!)
331 pSalData
->mpFirstInstance
= pInst
;
332 // this one is for outside AquaSalInstance::Yield
333 SalData::ensureThreadAutoreleasePool();
334 // no focus rects on NWF
335 ImplGetSVData()->maNWFData
.mbNoFocusRects
= true;
336 ImplGetSVData()->maNWFData
.mbNoActiveTabTextRaise
= true;
337 ImplGetSVData()->maNWFData
.mbCenteredTabs
= true;
338 ImplGetSVData()->maNWFData
.mbProgressNeedsErase
= true;
339 ImplGetSVData()->maNWFData
.mbCheckBoxNeedsErase
= true;
340 ImplGetSVData()->maNWFData
.mnStatusBarLowerRightOffset
= 10;
345 void DestroySalInstance( SalInstance
* pInst
)
350 AquaSalInstance::AquaSalInstance()
351 : maUserEventListMutex()
352 , maWaitingYieldCond()
354 mpSalYieldMutex
= new SalYieldMutex
;
355 mpSalYieldMutex
->acquire();
356 ::comphelper::SolarMutex::setSolarMutex( mpSalYieldMutex
);
357 maMainThread
= osl::Thread::getCurrentIdentifier();
358 mbWaitingYield
= false;
359 mnActivePrintJobs
= 0;
362 AquaSalInstance::~AquaSalInstance()
364 ::comphelper::SolarMutex::setSolarMutex( nullptr );
365 mpSalYieldMutex
->release();
366 delete mpSalYieldMutex
;
369 void AquaSalInstance::wakeupYield()
374 SalData::ensureThreadAutoreleasePool();
375 SAL_WNODEPRECATED_DECLARATIONS_PUSH
376 // 'NSApplicationDefined' is deprecated: first deprecated in macOS 10.12
377 NSEvent
* pEvent
= [NSEvent otherEventWithType
: NSApplicationDefined
378 location
: NSZeroPoint
383 subtype
: AquaSalInstance::YieldWakeupEvent
386 SAL_WNODEPRECATED_DECLARATIONS_POP
388 [NSApp postEvent
: pEvent atStart
: NO
];
392 void AquaSalInstance::PostUserEvent( AquaSalFrame
* pFrame
, SalEvent nType
, void* pData
)
395 osl::MutexGuard
g( maUserEventListMutex
);
396 maUserEvents
.push_back( SalUserEvent( pFrame
, pData
, nType
) );
398 // notify main loop that an event has arrived
402 comphelper::SolarMutex
* AquaSalInstance::GetYieldMutex()
404 return mpSalYieldMutex
;
407 sal_uLong
AquaSalInstance::ReleaseYieldMutex()
409 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
410 if ( pYieldMutex
->GetThreadId() ==
411 osl::Thread::getCurrentIdentifier() )
413 sal_uLong nCount
= pYieldMutex
->GetAcquireCount();
414 sal_uLong n
= nCount
;
417 pYieldMutex
->release();
427 void AquaSalInstance::AcquireYieldMutex( sal_uLong nCount
)
429 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
432 pYieldMutex
->acquire();
437 bool AquaSalInstance::CheckYieldMutex()
441 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
442 if ( pYieldMutex
->GetThreadId() != osl::Thread::getCurrentIdentifier())
450 bool AquaSalInstance::isNSAppThread() const
452 return osl::Thread::getCurrentIdentifier() == maMainThread
;
455 void AquaSalInstance::handleAppDefinedEvent( NSEvent
* pEvent
)
457 int nSubtype
= [pEvent subtype
];
460 case AppStartTimerEvent
:
461 AquaSalTimer::handleStartTimerEvent( pEvent
);
463 case AppEndLoopEvent
:
466 case AppExecuteSVMain
:
468 int nResult
= ImplSVMain();
480 #if !HAVE_FEATURE_MACOSX_SANDBOX
481 case AppleRemoteControlEvent
: // Defined in <apple_remote/RemoteMainController.h>
483 MediaCommand nCommand
;
484 SalData
* pSalData
= GetSalData();
485 bool bIsFullScreenMode
= false;
487 std::list
<AquaSalFrame
*>::iterator it
= pSalData
->maFrames
.begin();
488 while( it
!= pSalData
->maFrames
.end() )
490 if ( (*it
) && (*it
)->mbFullScreen
)
491 bIsFullScreenMode
= true;
495 switch ([pEvent data1
])
497 case kRemoteButtonPlay
:
498 nCommand
= bIsFullScreenMode
? MediaCommand::PlayPause
: MediaCommand::Play
;
501 // kept for experimentation purpose (scheduled for future implementation)
502 // case kRemoteButtonMenu: nCommand = MediaCommand::Menu; break;
504 case kRemoteButtonPlus
: nCommand
= MediaCommand::VolumeUp
; break;
506 case kRemoteButtonMinus
: nCommand
= MediaCommand::VolumeDown
; break;
508 case kRemoteButtonRight
: nCommand
= MediaCommand::NextTrack
; break;
510 case kRemoteButtonRight_Hold
: nCommand
= MediaCommand::NextTrackHold
; break;
512 case kRemoteButtonLeft
: nCommand
= MediaCommand::PreviousTrack
; break;
514 case kRemoteButtonLeft_Hold
: nCommand
= MediaCommand::Rewind
; break;
516 case kRemoteButtonPlay_Hold
: nCommand
= MediaCommand::PlayHold
; break;
518 case kRemoteButtonMenu_Hold
: nCommand
= MediaCommand::Stop
; break;
520 // FIXME : not detected
521 case kRemoteButtonPlus_Hold
:
522 case kRemoteButtonMinus_Hold
:
528 AquaSalFrame
* pFrame
= pSalData
->maFrames
.front();
529 vcl::Window
* pWindow
= pFrame
? pFrame
->GetWindow() : nullptr;
534 CommandMediaData
aMediaData(nCommand
);
535 CommandEvent
aCEvt( aPoint
, CommandEventId::Media
, FALSE
, &aMediaData
);
536 NotifyEvent
aNCmdEvt( MouseNotifyEvent::COMMAND
, pWindow
, &aCEvt
);
538 if ( !ImplCallPreNotify( aNCmdEvt
) )
539 pWindow
->Command( aCEvt
);
546 case YieldWakeupEvent
:
547 // do nothing, fall out of Yield
551 OSL_FAIL( "unhandled NSApplicationDefined event" );
556 class ReleasePoolHolder
558 NSAutoreleasePool
* mpPool
;
560 ReleasePoolHolder() : mpPool( [[NSAutoreleasePool alloc
] init
] ) {}
561 ~ReleasePoolHolder() { [mpPool release
]; }
564 SalYieldResult
AquaSalInstance::DoYield(bool bWait
, bool bHandleAllCurrentEvents
, sal_uLong
const nReleased
)
567 assert(nReleased
== 0); // not implemented
569 // ensure that the per thread autorelease pool is top level and
570 // will therefore not be destroyed by cocoa implicitly
571 SalData::ensureThreadAutoreleasePool();
573 // NSAutoreleasePool documentation suggests we should have
574 // an own pool for each yield level
575 ReleasePoolHolder aReleasePool
;
577 // Release all locks so that we don't deadlock when we pull pending
578 // events from the event queue
579 bool bDispatchUser
= true;
580 while( bDispatchUser
)
582 sal_uLong nCount
= ReleaseYieldMutex();
584 // get one user event
585 SalUserEvent
aEvent( nullptr, nullptr, SalEvent::NONE
);
587 osl::MutexGuard
g( maUserEventListMutex
);
588 if( ! maUserEvents
.empty() )
590 aEvent
= maUserEvents
.front();
591 maUserEvents
.pop_front();
594 bDispatchUser
= false;
596 AcquireYieldMutex( nCount
);
599 if( aEvent
.mpFrame
&& AquaSalFrame::isAlive( aEvent
.mpFrame
) )
601 aEvent
.mpFrame
->CallCallback( aEvent
.mnType
, aEvent
.mpData
);
602 maWaitingYieldCond
.set();
603 // return if only one event is asked for
604 if( ! bHandleAllCurrentEvents
)
605 return SalYieldResult::EVENT
;
609 // handle cocoa event queue
610 // cocoa events may be only handled in the thread the NSApp was created
611 bool bHadEvent
= false;
612 if( isNSAppThread() && mnActivePrintJobs
== 0 )
614 // we need to be woken up by a cocoa-event
615 // if a user event should be posted by the event handling below
616 bool bOldWaitingYield
= mbWaitingYield
;
617 mbWaitingYield
= bWait
;
619 // handle available events
620 NSEvent
* pEvent
= nil
;
623 sal_uLong nCount
= ReleaseYieldMutex();
625 SAL_WNODEPRECATED_DECLARATIONS_PUSH
626 // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
627 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask untilDate
: nil
628 SAL_WNODEPRECATED_DECLARATIONS_POP
629 inMode
: NSDefaultRunLoopMode dequeue
: YES
];
632 [NSApp sendEvent
: pEvent
];
635 [NSApp updateWindows
];
637 AcquireYieldMutex( nCount
);
638 } while( bHandleAllCurrentEvents
&& pEvent
);
640 // if we had no event yet, wait for one if requested
641 if( bWait
&& ! bHadEvent
)
643 sal_uLong nCount
= ReleaseYieldMutex();
645 NSDate
* pDt
= AquaSalTimer::pRunningTimer
? [AquaSalTimer::pRunningTimer fireDate
] : [NSDate distantFuture
];
646 SAL_WNODEPRECATED_DECLARATIONS_PUSH
647 // 'NSAnyEventMask' is deprecated: first deprecated in macOS 10.12
648 pEvent
= [NSApp nextEventMatchingMask
: NSAnyEventMask untilDate
: pDt
649 SAL_WNODEPRECATED_DECLARATIONS_POP
650 inMode
: NSDefaultRunLoopMode dequeue
: YES
];
652 [NSApp sendEvent
: pEvent
];
653 [NSApp updateWindows
];
655 AcquireYieldMutex( nCount
);
658 // FIXME: sometimes the NSTimer will never fire. Firing it by hand then
659 // fixes the problem even seems to set the correct next firing date
661 if( ! pEvent
&& AquaSalTimer::pRunningTimer
)
663 // this cause crashes on MacOSX 10.4
664 // [AquaSalTimer::pRunningTimer fire];
665 if (ImplGetSVData()->mpSalTimer
!= nullptr)
667 bool idle
= true; // TODO
668 ImplGetSVData()->mpSalTimer
->CallCallback( idle
);
673 mbWaitingYield
= bOldWaitingYield
;
675 // collect update rectangles
676 const std::list
< AquaSalFrame
* > rFrames( GetSalData()->maFrames
);
677 for( std::list
< AquaSalFrame
* >::const_iterator it
= rFrames
.begin(); it
!= rFrames
.end(); ++it
)
679 if( (*it
)->mbShown
&& ! (*it
)->maInvalidRect
.IsEmpty() )
681 (*it
)->Flush( (*it
)->maInvalidRect
);
682 (*it
)->maInvalidRect
.SetEmpty();
685 maWaitingYieldCond
.set();
690 // wait until any thread (most likely the main thread)
691 // has dispatched an event, cop out at 200 ms
692 maWaitingYieldCond
.reset();
693 TimeValue aVal
= { 0, 200000000 };
694 sal_uLong nCount
= ReleaseYieldMutex();
695 maWaitingYieldCond
.wait( &aVal
);
696 AcquireYieldMutex( nCount
);
699 // we get some apple events way too early
700 // before the application is ready to handle them,
701 // so their corresponding application events need to be delayed
702 // now is a good time to handle at least one of them
703 if( bWait
&& !aAppEventList
.empty() && ImplGetSVData()->maAppData
.mbInAppExecute
)
705 // make sure that only one application event is active at a time
706 static bool bInAppEvent
= false;
710 // get the next delayed application event
711 const ApplicationEvent
* pAppEvent
= aAppEventList
.front();
712 aAppEventList
.pop_front();
713 // handle one application event (no recursion)
714 const ImplSVData
* pSVData
= ImplGetSVData();
715 pSVData
->mpApp
->AppEvent( *pAppEvent
);
717 // allow the next delayed application event
722 return bHadEvent
? SalYieldResult::EVENT
: SalYieldResult::TIMEOUT
;
725 bool AquaSalInstance::AnyInput( VclInputFlags nType
)
727 if( nType
& VclInputFlags::APPEVENT
)
729 if( ! aAppEventList
.empty() )
731 if( nType
== VclInputFlags::APPEVENT
)
735 if( nType
& VclInputFlags::TIMER
)
737 if( AquaSalTimer::pRunningTimer
)
739 NSDate
* pDt
= [AquaSalTimer::pRunningTimer fireDate
];
740 if( pDt
&& [pDt timeIntervalSinceNow
] < 0 )
747 if (![NSThread isMainThread
])
750 unsigned/*NSUInteger*/ nEventMask
= 0;
751 SAL_WNODEPRECATED_DECLARATIONS_PUSH
752 // 'NSFlagsChangedMask' is deprecated: first deprecated in macOS 10.12
753 // 'NSKeyDownMask' is deprecated: first deprecated in macOS 10.12
754 // 'NSKeyUpMask' is deprecated: first deprecated in macOS 10.12
755 // 'NSLeftMouseDownMask' is deprecated: first deprecated in macOS 10.12
756 // 'NSLeftMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
757 // 'NSLeftMouseUpMask' is deprecated: first deprecated in macOS 10.12
758 // 'NSMouseEnteredMask' is deprecated: first deprecated in macOS 10.12
759 // 'NSMouseExitedMask' is deprecated: first deprecated in macOS 10.12
760 // 'NSOtherMouseDownMask' is deprecated: first deprecated in macOS 10.12
761 // 'NSOtherMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
762 // 'NSOtherMouseUpMask' is deprecated: first deprecated in macOS 10.12
763 // 'NSRightMouseDownMask' is deprecated: first deprecated in macOS 10.12
764 // 'NSRightMouseDraggedMask' is deprecated: first deprecated in macOS 10.12
765 // 'NSRightMouseUpMask' is deprecated: first deprecated in macOS 10.12
766 // 'NSScrollWheelMask' is deprecated: first deprecated in macOS 10.12
767 // 'NSTabletPoint' is deprecated: first deprecated in macOS 10.12
768 if( nType
& VclInputFlags::MOUSE
)
770 NSLeftMouseDownMask
| NSRightMouseDownMask
| NSOtherMouseDownMask
|
771 NSLeftMouseUpMask
| NSRightMouseUpMask
| NSOtherMouseUpMask
|
772 NSLeftMouseDraggedMask
| NSRightMouseDraggedMask
| NSOtherMouseDraggedMask
|
774 // NSMouseMovedMask |
775 NSMouseEnteredMask
| NSMouseExitedMask
;
776 if( nType
& VclInputFlags::KEYBOARD
)
777 nEventMask
|= NSKeyDownMask
| NSKeyUpMask
| NSFlagsChangedMask
;
778 if( nType
& VclInputFlags::OTHER
)
779 nEventMask
|= NSTabletPoint
;
780 SAL_WNODEPRECATED_DECLARATIONS_POP
781 // TODO: VclInputFlags::PAINT / more VclInputFlags::OTHER
785 NSEvent
* pEvent
= [NSApp nextEventMatchingMask
: nEventMask untilDate
: nil
786 inMode
: NSDefaultRunLoopMode dequeue
: NO
];
787 return (pEvent
!= nullptr);
790 SalFrame
* AquaSalInstance::CreateChildFrame( SystemParentData
*, SalFrameStyleFlags
/*nSalFrameStyle*/ )
795 SalFrame
* AquaSalInstance::CreateFrame( SalFrame
* pParent
, SalFrameStyleFlags nSalFrameStyle
)
797 SalData::ensureThreadAutoreleasePool();
799 SalFrame
* pFrame
= new AquaSalFrame( pParent
, nSalFrameStyle
);
803 void AquaSalInstance::DestroyFrame( SalFrame
* pFrame
)
808 SalObject
* AquaSalInstance::CreateObject( SalFrame
* pParent
, SystemWindowData
* pWindowData
, bool /* bShow */ )
810 AquaSalObject
*pObject
= nullptr;
813 pObject
= new AquaSalObject( static_cast<AquaSalFrame
*>(pParent
), pWindowData
);
818 void AquaSalInstance::DestroyObject( SalObject
* pObject
)
823 SalPrinter
* AquaSalInstance::CreatePrinter( SalInfoPrinter
* pInfoPrinter
)
825 return new AquaSalPrinter( dynamic_cast<AquaSalInfoPrinter
*>(pInfoPrinter
) );
828 void AquaSalInstance::DestroyPrinter( SalPrinter
* pPrinter
)
833 void AquaSalInstance::GetPrinterQueueInfo( ImplPrnQueueList
* pList
)
835 NSArray
* pNames
= [NSPrinter printerNames
];
836 NSArray
* pTypes
= [NSPrinter printerTypes
];
837 unsigned int nNameCount
= pNames
? [pNames count
] : 0;
838 unsigned int nTypeCount
= pTypes
? [pTypes count
] : 0;
839 SAL_WARN_IF( nTypeCount
!= nNameCount
, "vcl", "type count not equal to printer count" );
840 for( unsigned int i
= 0; i
< nNameCount
; i
++ )
842 NSString
* pName
= [pNames objectAtIndex
: i
];
843 NSString
* pType
= i
< nTypeCount
? [pTypes objectAtIndex
: i
] : nil
;
846 SalPrinterQueueInfo
* pInfo
= new SalPrinterQueueInfo
;
847 pInfo
->maPrinterName
= GetOUString( pName
);
849 pInfo
->maDriver
= GetOUString( pType
);
850 pInfo
->mnStatus
= PrintQueueFlags::NONE
;
852 pInfo
->mpSysData
= nullptr;
859 void AquaSalInstance::GetPrinterQueueState( SalPrinterQueueInfo
* )
863 void AquaSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo
* pInfo
)
868 OUString
AquaSalInstance::GetDefaultPrinter()
870 // #i113170# may not be the main thread if called from UNO API
871 SalData::ensureThreadAutoreleasePool();
873 if( maDefaultPrinter
.isEmpty() )
875 NSPrintInfo
* pPI
= [NSPrintInfo sharedPrintInfo
];
876 SAL_WARN_IF( !pPI
, "vcl", "no print info" );
879 NSPrinter
* pPr
= [pPI printer
];
880 SAL_WARN_IF( !pPr
, "vcl", "no printer in default info" );
883 NSString
* pDefName
= [pPr name
];
884 SAL_WARN_IF( !pDefName
, "vcl", "printer has no name" );
885 maDefaultPrinter
= GetOUString( pDefName
);
889 return maDefaultPrinter
;
892 SalInfoPrinter
* AquaSalInstance::CreateInfoPrinter( SalPrinterQueueInfo
* pQueueInfo
,
893 ImplJobSetup
* pSetupData
)
895 // #i113170# may not be the main thread if called from UNO API
896 SalData::ensureThreadAutoreleasePool();
898 SalInfoPrinter
* pNewInfoPrinter
= nullptr;
901 pNewInfoPrinter
= new AquaSalInfoPrinter( *pQueueInfo
);
903 pNewInfoPrinter
->SetPrinterData( pSetupData
);
906 return pNewInfoPrinter
;
909 void AquaSalInstance::DestroyInfoPrinter( SalInfoPrinter
* pPrinter
)
911 // #i113170# may not be the main thread if called from UNO API
912 SalData::ensureThreadAutoreleasePool();
917 OUString
AquaSalInstance::GetConnectionIdentifier()
922 // We need to re-encode file urls because osl_getFileURLFromSystemPath converts
923 // to UTF-8 before encoding non ascii characters, which is not what other apps expect.
924 static OUString
translateToExternalUrl(const OUString
& internalUrl
)
926 uno::Reference
< uno::XComponentContext
> context(
927 comphelper::getProcessComponentContext());
928 return uri::ExternalUriReferenceTranslator::create(context
)->translateToExternal(internalUrl
);
931 // #i104525# many versions of OSX have problems with some URLs:
932 // when an app requests OSX to add one of these URLs to the "Recent Items" list
933 // then this app gets killed (TextEdit, Preview, etc. and also OOo)
934 static bool isDangerousUrl( const OUString
& rUrl
)
936 // use a heuristic that detects all known cases since there is no official comment
937 // on the exact impact and root cause of the OSX bug
938 const int nLen
= rUrl
.getLength();
939 const sal_Unicode
* p
= rUrl
.getStr();
940 for( int i
= 0; i
< nLen
-3; ++i
, ++p
) {
944 if( (p
[1] == '2') && (p
[2] == '5') )
946 // escapes are considered to be UTF-8 encoded
947 // => check for invalid UTF-8 leading byte
948 if( (p
[1] != 'f') && (p
[1] != 'F') )
950 int cLowNibble
= p
[2];
951 if( (cLowNibble
>= '0' ) && (cLowNibble
<= '9'))
953 if( cLowNibble
>= 'a' )
954 cLowNibble
-= 'a' - 'A';
955 if( (cLowNibble
< 'A') || (cLowNibble
>= 'C'))
962 void AquaSalInstance::AddToRecentDocumentList(const OUString
& rFileUrl
, const OUString
& /*rMimeType*/, const OUString
& /*rDocumentService*/)
964 // Convert file URL for external use (see above)
965 OUString externalUrl
= translateToExternalUrl(rFileUrl
);
966 if( externalUrl
.isEmpty() )
967 externalUrl
= rFileUrl
;
969 if( !externalUrl
.isEmpty() && !isDangerousUrl( externalUrl
) )
971 NSString
* pString
= CreateNSString( externalUrl
);
972 NSURL
* pURL
= [NSURL URLWithString
: pString
];
976 NSDocumentController
* pCtrl
= [NSDocumentController sharedDocumentController
];
977 [pCtrl noteNewRecentDocumentURL
: pURL
];
984 SalTimer
* AquaSalInstance::CreateSalTimer()
986 return new AquaSalTimer();
989 SalSystem
* AquaSalInstance::CreateSalSystem()
991 return new AquaSalSystem();
994 SalBitmap
* AquaSalInstance::CreateSalBitmap()
996 return new QuartzSalBitmap();
999 SalSession
* AquaSalInstance::CreateSalSession()
1004 OUString
AquaSalInstance::getOSVersion()
1006 NSString
* versionString
= nullptr;
1007 NSString
* sysVersionDictionaryPath
= @
"/System/Library/CoreServices/SystemVersion.plist";
1008 NSDictionary
* sysVersionDict
= [ NSDictionary dictionaryWithContentsOfFile
: sysVersionDictionaryPath
];
1009 if ( sysVersionDict
)
1010 versionString
= [ sysVersionDict valueForKey
: @
"ProductVersion" ];
1012 OUString aVersion
= "Mac OS X ";
1013 if ( versionString
)
1014 aVersion
+= OUString::fromUtf8( [ versionString UTF8String
] );
1016 aVersion
+= "(unknown)";
1021 // YieldMutexReleaser
1022 YieldMutexReleaser::YieldMutexReleaser() : mnCount( 0 )
1024 SalData
* pSalData
= GetSalData();
1025 if( ! pSalData
->mpFirstInstance
->isNSAppThread() )
1027 SalData::ensureThreadAutoreleasePool();
1028 mnCount
= pSalData
->mpFirstInstance
->ReleaseYieldMutex();
1032 YieldMutexReleaser::~YieldMutexReleaser()
1035 GetSalData()->mpFirstInstance
->AcquireYieldMutex( mnCount
);
1038 CGImageRef
CreateCGImage( const Image
& rImage
)
1040 BitmapEx
aBmpEx( rImage
.GetBitmapEx() );
1041 Bitmap
aBmp( aBmpEx
.GetBitmap() );
1043 if( ! aBmp
|| ! aBmp
.ImplGetImpBitmap() )
1046 // simple case, no transparency
1047 QuartzSalBitmap
* pSalBmp
= static_cast<QuartzSalBitmap
*>(aBmp
.ImplGetImpBitmap()->ImplGetSalBitmap());
1052 CGImageRef xImage
= nullptr;
1053 if( ! (aBmpEx
.IsAlpha() || aBmpEx
.IsTransparent() ) )
1054 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1055 else if( aBmpEx
.IsAlpha() )
1057 AlphaMask
aAlphaMask( aBmpEx
.GetAlpha() );
1058 Bitmap
aMask( aAlphaMask
.GetBitmap() );
1059 QuartzSalBitmap
* pMaskBmp
= static_cast<QuartzSalBitmap
*>(aMask
.ImplGetImpBitmap()->ImplGetSalBitmap());
1061 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1063 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1065 else if( aBmpEx
.GetTransparentType() == TransparentType::Bitmap
)
1067 Bitmap
aMask( aBmpEx
.GetMask() );
1068 QuartzSalBitmap
* pMaskBmp
= static_cast<QuartzSalBitmap
*>(aMask
.ImplGetImpBitmap()->ImplGetSalBitmap());
1070 xImage
= pSalBmp
->CreateWithMask( *pMaskBmp
, 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1072 xImage
= pSalBmp
->CreateCroppedImage( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
);
1074 else if( aBmpEx
.GetTransparentType() == TransparentType::Color
)
1076 Color
aTransColor( aBmpEx
.GetTransparentColor() );
1077 SalColor nTransColor
= MAKE_SALCOLOR( aTransColor
.GetRed(), aTransColor
.GetGreen(), aTransColor
.GetBlue() );
1078 xImage
= pSalBmp
->CreateColorMask( 0, 0, pSalBmp
->mnWidth
, pSalBmp
->mnHeight
, nTransColor
);
1084 NSImage
* CreateNSImage( const Image
& rImage
)
1086 CGImageRef xImage
= CreateCGImage( rImage
);
1091 Size
aSize( rImage
.GetSizePixel() );
1092 NSImage
* pImage
= [[NSImage alloc
] initWithSize
: NSMakeSize( aSize
.Width(), aSize
.Height() )];
1095 [pImage lockFocusFlipped
:YES
];
1096 NSGraphicsContext
* pContext
= [NSGraphicsContext currentContext
];
1097 CGContextRef rCGContext
= static_cast<CGContextRef
>([pContext graphicsPort
]);
1099 const CGRect aDstRect
= { {0, 0}, { static_cast<CGFloat
>(aSize
.Width()), static_cast<CGFloat
>(aSize
.Height()) } };
1100 CGContextDrawImage( rCGContext
, aDstRect
, xImage
);
1102 [pImage unlockFocus
];
1105 CGImageRelease( xImage
);
1111 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */