1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: salinst.cxx,v $
10 * $Revision: 1.8.74.1 $
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 ************************************************************************/
32 #define INCL_DOSMODULEMGR
33 #define INCL_DOSPROCESS
39 #define _SV_SALINST_CXX
41 #ifndef _VOS_MUTEX_HXX
42 #include <vos/mutex.hxx>
44 #include <tools/debug.hxx>
46 #ifndef _SV_SALIDS_HRC
49 #include <vcl/salatype.hxx>
50 #include <saldata.hxx>
56 #include <vcl/salimestatus.hxx>
57 #include <vcl/timer.hxx>
59 // =======================================================================
61 void SalAbort( const XubString
& rErrorText
)
65 if( !rErrorText
.Len() )
66 fprintf( stderr
, "Application Error " );
68 fprintf( stderr
, "%s ",
69 ByteString( rErrorText
, gsl_getSystemTextEncoding() ).GetBuffer() );
73 // =======================================================================
75 ULONG
GetCurrentThreadId()
80 DosGetInfoBlocks( &pptib
, &pppib
);
81 return pptib
->tib_ptib2
->tib2_ultid
;
84 // =======================================================================
86 MRESULT EXPENTRY
SalComWndProc( HWND hWnd
, ULONG nMsg
, MPARAM nMP1
, MPARAM nMP2
);
88 // =======================================================================
90 class SalYieldMutex
: public vos::OMutex
93 Os2SalInstance
* mpInstData
;
98 SalYieldMutex( Os2SalInstance
* pInstData
);
100 virtual void SAL_CALL
acquire();
101 virtual void SAL_CALL
release();
102 virtual sal_Bool SAL_CALL
tryToAcquire();
104 ULONG
GetAcquireCount( ULONG nThreadId
);
107 // -----------------------------------------------------------------------
109 SalYieldMutex::SalYieldMutex( Os2SalInstance
* pInstData
)
111 mpInstData
= pInstData
;
116 // -----------------------------------------------------------------------
118 void SalYieldMutex::acquire()
122 mnThreadId
= GetCurrentThreadId();
125 // -----------------------------------------------------------------------
127 void SalYieldMutex::release()
129 ULONG nThreadId
= GetCurrentThreadId();
130 if ( mnThreadId
!= nThreadId
)
134 SalData
* pSalData
= GetSalData();
135 if ( pSalData
->mnAppThreadId
!= nThreadId
)
139 mpInstData
->mpSalWaitMutex
->acquire();
140 if ( mpInstData
->mnYieldWaitCount
)
141 WinPostMsg( mpInstData
->mhComWnd
, SAL_MSG_RELEASEWAITYIELD
, 0, 0 );
145 mpInstData
->mpSalWaitMutex
->release();
163 // -----------------------------------------------------------------------
165 sal_Bool
SalYieldMutex::tryToAcquire()
167 if ( OMutex::tryToAcquire() )
170 mnThreadId
= GetCurrentThreadId();
177 // -----------------------------------------------------------------------
179 ULONG
SalYieldMutex::GetAcquireCount( ULONG nThreadId
)
181 if ( nThreadId
== mnThreadId
)
187 // -----------------------------------------------------------------------
189 void ImplSalYieldMutexAcquireWithWait()
191 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
195 // If we are the main thread, then we must wait with wait, because
196 // in if we don't reschedule, then we create deadlocks if a Windows
197 // Function is called from another thread. If we arn't the main thread,
198 // than we call qcquire directly.
199 ULONG nThreadId
= GetCurrentThreadId();
200 SalData
* pSalData
= GetSalData();
201 if ( pSalData
->mnAppThreadId
== nThreadId
)
203 // Wenn wir den Mutex nicht bekommen, muessen wir solange
204 // warten, bis wir Ihn bekommen
205 BOOL bAcquire
= FALSE
;
208 if ( pInst
->mpSalYieldMutex
->tryToAcquire() )
212 pInst
->mpSalWaitMutex
->acquire();
213 if ( pInst
->mpSalYieldMutex
->tryToAcquire() )
216 pInst
->mpSalWaitMutex
->release();
220 pInst
->mnYieldWaitCount
++;
221 pInst
->mpSalWaitMutex
->release();
223 WinGetMsg( pSalData
->mhAB
, &aTmpMsg
, pInst
->mhComWnd
, SAL_MSG_RELEASEWAITYIELD
, SAL_MSG_RELEASEWAITYIELD
);
224 pInst
->mnYieldWaitCount
--;
225 if ( pInst
->mnYieldWaitCount
)
226 WinPostMsg( pInst
->mhComWnd
, SAL_MSG_RELEASEWAITYIELD
, 0 , 0 );
233 pInst
->mpSalYieldMutex
->acquire();
236 // -----------------------------------------------------------------------
238 BOOL
ImplSalYieldMutexTryToAcquire()
240 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
242 return pInst
->mpSalYieldMutex
->tryToAcquire();
247 // -----------------------------------------------------------------------
249 void ImplSalYieldMutexAcquire()
251 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
253 pInst
->mpSalYieldMutex
->acquire();
256 // -----------------------------------------------------------------------
258 void ImplSalYieldMutexRelease()
260 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
262 pInst
->mpSalYieldMutex
->release();
265 // -----------------------------------------------------------------------
267 ULONG
ImplSalReleaseYieldMutex()
269 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
273 SalYieldMutex
* pYieldMutex
= pInst
->mpSalYieldMutex
;
274 ULONG nCount
= pYieldMutex
->GetAcquireCount( GetCurrentThreadId() );
278 pYieldMutex
->release();
285 // -----------------------------------------------------------------------
287 void ImplSalAcquireYieldMutex( ULONG nCount
)
289 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
293 SalYieldMutex
* pYieldMutex
= pInst
->mpSalYieldMutex
;
296 pYieldMutex
->acquire();
301 // -----------------------------------------------------------------------
305 void ImplDbgTestSolarMutex()
307 SalData
* pSalData
= GetSalData();
308 ULONG nCurThreadId
= GetCurrentThreadId();
309 if ( pSalData
->mnAppThreadId
!= nCurThreadId
)
311 if ( pSalData
->mpFirstInstance
)
313 SalYieldMutex
* pYieldMutex
= pSalData
->mpFirstInstance
->mpSalYieldMutex
;
314 if ( pYieldMutex
->mnThreadId
!= nCurThreadId
)
316 DBG_ERROR( "SolarMutex not locked, and not thread save code in VCL is called from outside of the main thread" );
322 if ( pSalData
->mpFirstInstance
)
324 SalYieldMutex
* pYieldMutex
= pSalData
->mpFirstInstance
->mpSalYieldMutex
;
325 if ( pYieldMutex
->mnThreadId
!= nCurThreadId
)
327 DBG_ERROR( "SolarMutex not locked in the main thread" );
335 // =======================================================================
339 SalData
* pSalData
= new SalData
;
340 memset( pSalData
, 0, sizeof( SalData
) );
341 SetSalData( pSalData
);
344 // -----------------------------------------------------------------------
348 SalData
* pSalData
= GetSalData();
349 if ( pSalData
->mpFontMetrics
)
350 delete pSalData
->mpFontMetrics
;
355 // -----------------------------------------------------------------------
363 SalData
* pData
= GetAppSalData();
364 #if OSL_DEBUG_LEVEL>0
365 printf("InitSalMain\n");
368 // morph application to PM
369 DosGetInfoBlocks(&tib
, &pib
);
370 // Change flag from VIO to PM:
371 if (pib
->pib_ultype
==2) pib
->pib_ultype
= 3;
373 // create anchor block
374 hAB
= WinInitialize( 0 );
378 // create message queue
379 hMQ
= WinCreateMsgQueue( hAB
, 60 );
386 if ( pData
) // Im AppServer NULL
388 // Ankerblock und Messagequeue merken
397 #if OSL_DEBUG_LEVEL>0
398 printf("DeInitSalMain\n");
401 SalData
* pData
= GetAppSalData();
402 // destroy message queue and anchor block
403 WinDestroyMsgQueue( pData
->mhMQ
);
404 WinTerminate( pData
->mhAB
);
408 // -----------------------------------------------------------------------
410 SalInstance
* CreateSalInstance()
412 SalData
* pSalData
= GetSalData();
414 // determine the os2 version
417 DosQuerySysInfo( QSV_VERSION_MAJOR
, QSV_VERSION_MAJOR
, &nMayor
, sizeof( nMayor
) );
418 DosQuerySysInfo( QSV_VERSION_MINOR
, QSV_VERSION_MINOR
, &nMinor
, sizeof( nMinor
) );
419 aSalShlData
.mnVersion
= (USHORT
)(nMayor
*10 + nMinor
);
421 pSalData
->mnAppThreadId
= GetCurrentThreadId();
423 // register frame class
424 if ( !WinRegisterClass( pSalData
->mhAB
, (PSZ
)SAL_FRAME_CLASSNAME
,
425 (PFNWP
)SalFrameWndProc
, CS_MOVENOTIFY
/* 17/08 CS_HITTEST | CS_MOVENOTIFY */,
426 SAL_FRAME_WNDEXTRA
) )
430 // register subframe class
431 if ( !WinRegisterClass( pSalData
->mhAB
, (PSZ
)SAL_SUBFRAME_CLASSNAME
,
432 (PFNWP
)SalFrameWndProc
, CS_SAVEBITS
| CS_MOVENOTIFY
,
433 SAL_FRAME_WNDEXTRA
) )
437 // register object class
438 if ( !WinRegisterClass( pSalData
->mhAB
, (PSZ
)SAL_COM_CLASSNAME
,
439 (PFNWP
)SalComWndProc
, 0, 0 ))
444 HWND hComWnd
= WinCreateWindow( HWND_OBJECT
, (PCSZ
)SAL_COM_CLASSNAME
,
445 (PCSZ
)"", 0, 0, 0, 0, 0,
446 HWND_OBJECT
, HWND_TOP
,
451 #if OSL_DEBUG_LEVEL>0
452 debug_printf("CreateSalInstance hComWnd %x\n", hComWnd
);
454 Os2SalInstance
* pInst
= new Os2SalInstance
;
456 // init instance (only one instance in this version !!!)
457 pSalData
->mpFirstInstance
= pInst
;
458 pInst
->mhAB
= pSalData
->mhAB
;
459 pInst
->mhMQ
= pSalData
->mhMQ
;
460 pInst
->mnArgc
= pSalData
->mnArgc
;
461 pInst
->mpArgv
= pSalData
->mpArgv
;
462 pInst
->mhComWnd
= hComWnd
;
465 ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT
, pInst
->mhAppIcon
);
467 // init static GDI Data
473 // -----------------------------------------------------------------------
475 void DestroySalInstance( SalInstance
* pInst
)
477 SalData
* pSalData
= GetSalData();
479 // (only one instance in this version !!!)
483 // IME-Daten freigeben
484 if ( pSalData
->mpIMEData
)
485 ImplReleaseSALIMEData();
489 if ( pSalData
->mpFirstInstance
== pInst
)
490 pSalData
->mpFirstInstance
= NULL
;
495 // -----------------------------------------------------------------------
497 Os2SalInstance::Os2SalInstance()
500 mpSalYieldMutex
= new SalYieldMutex( this );
501 mpSalWaitMutex
= new vos::OMutex
;
502 mnYieldWaitCount
= 0;
503 mpSalYieldMutex
->acquire();
506 // -----------------------------------------------------------------------
508 Os2SalInstance::~Os2SalInstance()
510 mpSalYieldMutex
->release();
511 delete mpSalYieldMutex
;
512 delete mpSalWaitMutex
;
513 WinDestroyWindow( mhComWnd
);
516 // -----------------------------------------------------------------------
518 vos::IMutex
* Os2SalInstance::GetYieldMutex()
520 return mpSalYieldMutex
;
522 // -----------------------------------------------------------------------
524 ULONG
Os2SalInstance::ReleaseYieldMutex()
526 return ImplSalReleaseYieldMutex();
529 // -----------------------------------------------------------------------
531 void Os2SalInstance::AcquireYieldMutex( ULONG nCount
)
533 ImplSalAcquireYieldMutex( nCount
);
536 // -----------------------------------------------------------------------
538 static void ImplSalYield( BOOL bWait
, BOOL bHandleAllCurrentEvents
)
541 bool bWasMsg
= false, bOneEvent
= false;
544 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
545 int nMaxEvents
= bHandleAllCurrentEvents
? 100 : 1;
548 if ( WinPeekMsg( pInst
->mhAB
, &aMsg
, 0, 0, 0, PM_REMOVE
) )
550 WinDispatchMsg( pInst
->mhAB
, &aMsg
);
551 bOneEvent
= bWasMsg
= true;
552 if (aMsg
.msg
== WM_QUIT
)
557 } while( --nMaxEvents
&& bOneEvent
);
559 if ( bWait
&& ! bWasMsg
)
561 if ( WinGetMsg( pInst
->mhAB
, &aMsg
, 0, 0, 0 ) )
562 WinDispatchMsg( pInst
->mhAB
, &aMsg
);
569 ImplSalYieldMutexAcquireWithWait();
570 Os2SalFrame
* pFrame
= GetSalData()->mpFirstFrame
;
573 if (pFrame
->CallCallback( SALEVENT_SHUTDOWN
, 0 ))
574 WinCancelShutdown( pFrame
->mhAB
, FALSE
);
576 ImplSalYieldMutexRelease();
581 // -----------------------------------------------------------------------
583 void Os2SalInstance::Yield( bool bWait
, bool bHandleAllCurrentEvents
)
585 SalYieldMutex
* pYieldMutex
= mpSalYieldMutex
;
586 SalData
* pSalData
= GetSalData();
587 ULONG nCurThreadId
= GetCurrentThreadId();
588 ULONG nCount
= pYieldMutex
->GetAcquireCount( nCurThreadId
);
592 pYieldMutex
->release();
595 if ( pSalData
->mnAppThreadId
!= nCurThreadId
)
597 // #97739# A SendMessage call blocks until the called thread (here: the main thread)
598 // returns. During a yield however, messages are processed in the main thread that might
599 // result in a new message loop due to opening a dialog. Thus, SendMessage would not
600 // return which will block this thread!
601 // Solution: just give up the time slice and hope that messages are processed
602 // by the main thread anyway (where all windows are created)
603 // If the mainthread is not currently handling messages, then our SendMessage would
604 // also do nothing, so this seems to be reasonable.
606 // #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
607 if( ImplGetSVData()->maAppData
.mnModalMode
)
610 WinSendMsg( mhComWnd
, SAL_MSG_THREADYIELD
, (MPARAM
)bWait
, (MPARAM
)bHandleAllCurrentEvents
);
615 pYieldMutex
->acquire();
621 ImplSalYield( bWait
, bHandleAllCurrentEvents
);
626 ImplSalYieldMutexAcquireWithWait();
632 // -----------------------------------------------------------------------
634 MRESULT EXPENTRY
SalComWndProc( HWND hWnd
, ULONG nMsg
,
635 MPARAM nMP1
, MPARAM nMP2
)
637 //debug_printf( "SalComWndProc hWnd 0x%x nMsg %d\n", hWnd, nMsg);
641 case SAL_MSG_PRINTABORTJOB
:
642 //ImplSalPrinterAbortJobAsync( (HDC)wParam );
644 case SAL_MSG_THREADYIELD
:
645 ImplSalYield( (bool)nMP1
, (bool) nMP2
);
647 // If we get this message, because another GetMessage() call
648 // has recieved this message, we must post this message to
649 // us again, because in the other case we wait forever.
650 case SAL_MSG_RELEASEWAITYIELD
:
652 Os2SalInstance
* pInst
= GetSalData()->mpFirstInstance
;
653 if ( pInst
&& pInst
->mnYieldWaitCount
)
654 WinPostMsg( hWnd
, SAL_MSG_RELEASEWAITYIELD
, nMP1
, nMP2
);
657 case SAL_MSG_STARTTIMER
:
658 ImplSalStartTimer( (ULONG
)nMP2
, FALSE
);
660 case SAL_MSG_CREATEFRAME
:
661 return (MRESULT
)ImplSalCreateFrame( GetSalData()->mpFirstInstance
, (HWND
)nMP2
, (ULONG
)nMP1
);
662 case SAL_MSG_DESTROYFRAME
:
663 delete (SalFrame
*)nMP2
;
665 case SAL_MSG_DESTROYHWND
:
666 //We only destroy the native window here. We do NOT destroy the SalFrame contained
667 //in the structure (GetWindowPtr()).
668 if (WinDestroyWindow((HWND
)nMP2
) == 0)
670 OSL_ENSURE(0, "DestroyWindow failed!");
671 //Failure: We remove the SalFrame from the window structure. So we avoid that
672 // the window structure may contain an invalid pointer, once the SalFrame is deleted.
673 SetWindowPtr((HWND
)nMP2
, 0);
676 case SAL_MSG_CREATEOBJECT
:
677 return (MRESULT
)ImplSalCreateObject( GetSalData()->mpFirstInstance
, (Os2SalFrame
*)(ULONG
)nMP2
);
678 case SAL_MSG_DESTROYOBJECT
:
679 delete (SalObject
*)nMP2
;
681 case SAL_MSG_CREATESOUND
:
682 //return (MRESULT)((Os2SalSound*)nMP2)->ImplCreate();
684 case SAL_MSG_DESTROYSOUND
:
685 //((Os2SalSound*)nMP2)->ImplDestroy();
687 case SAL_MSG_POSTTIMER
:
688 SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE
, (ULONG
)nMP2
);
691 SalTimerProc( hWnd
, 0, 0, 0 );
695 return WinDefWindowProc( hWnd
, nMsg
, nMP1
, nMP2
);
698 // -----------------------------------------------------------------------
700 bool Os2SalInstance::AnyInput( USHORT nType
)
702 SalData
* pSalData
= GetSalData();
705 if ( (nType
& (INPUT_ANY
)) == INPUT_ANY
)
708 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0, 0, 0, PM_NOREMOVE
) )
713 if ( nType
& INPUT_MOUSE
)
715 // Test auf Mouseinput
716 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0,
717 WM_MOUSEFIRST
, WM_MOUSELAST
, PM_NOREMOVE
) )
721 if ( nType
& INPUT_KEYBOARD
)
724 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0,
725 WM_CHAR
, WM_CHAR
, PM_NOREMOVE
) )
726 return !(SHORT1FROMMP( aQMSG
.mp1
) & KC_KEYUP
);
729 if ( nType
& INPUT_PAINT
)
731 // Test auf Paintinput
732 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0,
733 WM_PAINT
, WM_PAINT
, PM_NOREMOVE
) )
737 if ( nType
& INPUT_TIMER
)
739 // Test auf Timerinput
740 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0,
741 WM_TIMER
, WM_TIMER
, PM_NOREMOVE
) )
745 if ( nType
& INPUT_OTHER
)
747 // Test auf sonstigen Input
748 if ( WinPeekMsg( pSalData
->mhAB
, &aQMSG
, 0, 0, 0, PM_NOREMOVE
) )
756 // -----------------------------------------------------------------------
758 SalFrame
* Os2SalInstance::CreateChildFrame( SystemParentData
* pSystemParentData
, ULONG nSalFrameStyle
)
760 // Um auf Main-Thread umzuschalten
761 return (SalFrame
*)WinSendMsg( mhComWnd
, SAL_MSG_CREATEFRAME
, (MPARAM
)nSalFrameStyle
, (MPARAM
)pSystemParentData
->hWnd
);
764 // -----------------------------------------------------------------------
766 SalFrame
* Os2SalInstance::CreateFrame( SalFrame
* pParent
, ULONG nSalFrameStyle
)
768 // Um auf Main-Thread umzuschalten
770 //31/05/06 YD use client as owner(parent) so positioning will not need to
771 // take care of borders and captions
773 mhWndClient
= static_cast<Os2SalFrame
*>(pParent
)->mhWndClient
;
776 return (SalFrame
*)WinSendMsg( mhComWnd
, SAL_MSG_CREATEFRAME
, (MPARAM
)nSalFrameStyle
, (MPARAM
)mhWndClient
);
780 // -----------------------------------------------------------------------
782 void Os2SalInstance::DestroyFrame( SalFrame
* pFrame
)
784 WinSendMsg( mhComWnd
, SAL_MSG_DESTROYFRAME
, 0, (MPARAM
)pFrame
);
787 // -----------------------------------------------------------------------
789 SalObject
* Os2SalInstance::CreateObject( SalFrame
* pParent
,
790 SystemWindowData
* /*pWindowData*/, // SystemWindowData meaningless on Windows
793 // Um auf Main-Thread umzuschalten
794 return (SalObject
*)WinSendMsg( mhComWnd
, SAL_MSG_CREATEOBJECT
, 0, (MPARAM
)pParent
);
798 // -----------------------------------------------------------------------
800 void Os2SalInstance::DestroyObject( SalObject
* pObject
)
802 WinSendMsg( mhComWnd
, SAL_MSG_DESTROYOBJECT
, 0, (MPARAM
)pObject
);
805 // -----------------------------------------------------------------------
807 void* Os2SalInstance::GetConnectionIdentifier( ConnectionIdentifierType
& rReturnedType
, int& rReturnedBytes
)
810 rReturnedType
= AsciiCString
;
814 void Os2SalInstance::AddToRecentDocumentList(const rtl::OUString
& /*rFileUrl*/, const rtl::OUString
& /*rMimeType*/)
818 // -----------------------------------------------------------------------
820 SalTimer
* Os2SalInstance::CreateSalTimer()
822 return new Os2SalTimer();
825 // -----------------------------------------------------------------------
827 SalBitmap
* Os2SalInstance::CreateSalBitmap()
829 return new Os2SalBitmap();
832 // -----------------------------------------------------------------------
834 class Os2ImeStatus
: public SalI18NImeStatus
838 virtual ~Os2ImeStatus() {}
840 // asks whether there is a status window available
841 // to toggle into menubar
842 virtual bool canToggle() { return false; }
843 virtual void toggle() {}
846 SalI18NImeStatus
* Os2SalInstance::CreateI18NImeStatus()
848 return new Os2ImeStatus();
851 // -----------------------------------------------------------------------
853 const ::rtl::OUString
& SalGetDesktopEnvironment()
855 static ::rtl::OUString
aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "OS/2" ) );
856 return aDesktopEnvironment
;
859 SalSession
* Os2SalInstance::CreateSalSession()