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: saldata.cxx,v $
10 * $Revision: 1.58.98.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 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
38 // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
46 #include <stdio.h> // snprintf, seems not to be in namespace std on every platform
50 #include <sys/resource.h>
52 #include <sys/systeminfo.h>
58 #include <sys/types.h>
62 #include <vos/process.hxx>
63 #ifndef _VOS_MUTEX_HXX
64 #include <vos/mutex.hxx>
68 #include <saldisp.hxx>
69 #include <saldata.hxx>
70 #include <vcl/salinst.hxx>
72 #include <osl/signal.h>
73 #include <osl/thread.h>
74 #include <osl/process.h>
75 #include <rtl/strbuf.hxx>
76 #ifndef _RTL_BOOTSTRAP_HXX
77 #include <rtl/bootstrap.hxx>
80 #include <tools/debug.hxx>
82 #include <vcl/svapp.hxx>
83 #include "i18n_im.hxx"
84 #include "i18n_xkb.hxx"
86 // -=-= <signal.h> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
95 #define SIGIOT SIGABRT
99 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
100 static const struct timeval noyield__
= { 0, 0 };
101 static const struct timeval yield__
= { 0, 10000 };
103 static const char* XRequest
[] = {
104 // see /usr/lib/X11/XErrorDB, /usr/openwin/lib/XErrorDB ...
107 "X_ChangeWindowAttributes",
108 "X_GetWindowAttributes",
110 "X_DestroySubwindows",
127 "X_SetSelectionOwner",
128 "X_GetSelectionOwner",
129 "X_ConvertSelection",
135 "X_ChangeActivePointerGrab",
153 "X_QueryTextExtents",
155 "X_ListFontsWithInfo",
164 "X_SetClipRectangles",
175 "X_PolyFillRectangle",
185 "X_CopyColormapAndFree",
187 "X_UninstallColormap",
188 "X_ListInstalledColormaps",
192 "X_AllocColorPlanes",
199 "X_CreateGlyphCursor",
205 "X_ChangeKeyboardMapping",
206 "X_GetKeyboardMapping",
207 "X_ChangeKeyboardControl",
208 "X_GetKeyboardControl",
210 "X_ChangePointerControl",
211 "X_GetPointerControl",
216 "X_SetAccessControl",
217 "X_SetCloseDownMode",
219 "X_RotateProperties",
220 "X_ForceScreenSaver",
221 "X_SetPointerMapping",
222 "X_GetPointerMapping",
223 "X_SetModifierMapping",
224 "X_GetModifierMapping",
235 // -=-= C statics =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
236 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
238 int X11SalData::XErrorHdl( Display
*pDisplay
, XErrorEvent
*pEvent
)
240 GetX11SalData()->XError( pDisplay
, pEvent
);
244 int X11SalData::XIOErrorHdl( Display
* )
246 /* #106197# hack: until a real shutdown procedure exists
249 if( ImplGetSVData()->maAppData
.mbAppQuit
)
253 if( ! SessionManagerClient::checkDocumentsSaved() )
254 /* oslSignalAction eToDo = */ osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR
, NULL
);
256 std::fprintf( stderr
, "X IO Error\n" );
257 std::fflush( stdout
);
258 std::fflush( stderr
);
260 /* #106197# the same reasons to use _exit instead of exit in salmain
261 * do apply here. Since there is nothing to be done after an XIO
262 * error we have to _exit immediately.
268 // -=-= SalData =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
269 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
272 X11SalData::X11SalData()
274 bNoExceptions_
= !!getenv( "SAL_NOSEGV" );
277 m_pSalDisplay
= NULL
;
281 hMainThread_
= pthread_self();
284 X11SalData::~X11SalData()
289 void X11SalData::DeleteDisplay()
291 delete m_pSalDisplay
;
292 m_pSalDisplay
= NULL
;
297 void X11SalData::Init()
299 pXLib_
= new SalXLib();
303 void X11SalData::initNWF( void )
307 void X11SalData::deInitNWF( void )
311 // -=-= SalXLib =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
312 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
315 m_aTimeout
.tv_sec
= 0;
316 m_aTimeout
.tv_usec
= 0;
320 FD_ZERO( &aReadFDS_
);
321 FD_ZERO( &aExceptionFDS_
);
323 m_pTimeoutFDS
[0] = m_pTimeoutFDS
[1] = -1;
324 if (pipe (m_pTimeoutFDS
) != -1)
326 // initialize 'wakeup' pipe.
329 // set close-on-exec descriptor flag.
330 if ((flags
= fcntl (m_pTimeoutFDS
[0], F_GETFD
)) != -1)
333 fcntl (m_pTimeoutFDS
[0], F_SETFD
, flags
);
335 if ((flags
= fcntl (m_pTimeoutFDS
[1], F_GETFD
)) != -1)
338 fcntl (m_pTimeoutFDS
[1], F_SETFD
, flags
);
341 // set non-blocking I/O flag.
342 if ((flags
= fcntl (m_pTimeoutFDS
[0], F_GETFL
)) != -1)
345 fcntl (m_pTimeoutFDS
[0], F_SETFL
, flags
);
347 if ((flags
= fcntl (m_pTimeoutFDS
[1], F_GETFL
)) != -1)
350 fcntl (m_pTimeoutFDS
[1], F_SETFL
, flags
);
353 // insert [0] into read descriptor set.
354 FD_SET( m_pTimeoutFDS
[0], &aReadFDS_
);
355 nFDs_
= m_pTimeoutFDS
[0] + 1;
358 PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
359 m_bHaveSystemChildFrames
= false;
364 // close 'wakeup' pipe.
365 close (m_pTimeoutFDS
[0]);
366 close (m_pTimeoutFDS
[1]);
371 void SalXLib::PushXErrorLevel( bool bIgnore
)
373 m_aXErrorHandlerStack
.push_back( XErrorStackEntry() );
374 XErrorStackEntry
& rEnt
= m_aXErrorHandlerStack
.back();
376 rEnt
.m_bIgnore
= bIgnore
;
377 rEnt
.m_nLastErrorRequest
= 0;
378 rEnt
.m_aHandler
= XSetErrorHandler( (XErrorHandler
)X11SalData::XErrorHdl
);
381 void SalXLib::PopXErrorLevel()
383 if( m_aXErrorHandlerStack
.size() )
385 XSetErrorHandler( m_aXErrorHandlerStack
.back().m_aHandler
);
386 m_aXErrorHandlerStack
.pop_back();
392 SalI18N_InputMethod
* pInputMethod
= new SalI18N_InputMethod
;
393 pInputMethod
->SetLocale();
397 * open connection to X11 Display
399 * o -display command line parameter,
400 * o $DISPLAY environment variable
404 Display
*pDisp
= NULL
;
406 // is there a -display command line parameter?
407 vos::OExtCommandLine aCommandLine
;
408 sal_uInt32 nParams
= aCommandLine
.getCommandArgCount();
409 rtl::OUString aParam
;
410 rtl::OString aDisplay
;
411 for (USHORT i
=0; i
<nParams
; i
++)
413 aCommandLine
.getCommandArg(i
, aParam
);
414 if (aParam
.equalsAscii("-display"))
416 aCommandLine
.getCommandArg(i
+1, aParam
);
417 aDisplay
= rtl::OUStringToOString(
418 aParam
, osl_getThreadTextEncoding());
420 if ((pDisp
= XOpenDisplay(aDisplay
.getStr()))!=NULL
)
423 * if a -display switch was used, we need
424 * to set the environment accoringly since
425 * the clipboard build another connection
426 * to the xserver using $DISPLAY
428 const char envpre
[] = "DISPLAY=";
429 char *envstr
= new char[sizeof(envpre
)+aDisplay
.getLength()];
430 snprintf(envstr
, sizeof(envpre
)+aDisplay
.getLength(), "DISPLAY=%s", aDisplay
.getStr());
437 if (!pDisp
&& !aDisplay
.getLength())
439 // Open $DISPLAY or default...
440 char *pDisplay
= getenv("DISPLAY");
441 if (pDisplay
!= NULL
)
442 aDisplay
= rtl::OString(pDisplay
);
443 pDisp
= XOpenDisplay(pDisplay
);
448 rtl::OUString aProgramFileURL
;
449 osl_getExecutableFile( &aProgramFileURL
.pData
);
450 rtl::OUString aProgramSystemPath
;
451 osl_getSystemPathFromFileURL (aProgramFileURL
.pData
, &aProgramSystemPath
.pData
);
452 rtl::OString aProgramName
= rtl::OUStringToOString(
454 osl_getThreadTextEncoding() );
455 std::fprintf( stderr
, "%s X11 error: Can't open display: %s\n",
456 aProgramName
.getStr(), aDisplay
.getStr());
457 std::fprintf( stderr
, " Set DISPLAY environment variable, use -display option\n");
458 std::fprintf( stderr
, " or check permissions of your X-Server\n");
459 std::fprintf( stderr
, " (See \"man X\" resp. \"man xhost\" for details)\n");
460 std::fflush( stderr
);
464 XSetIOErrorHandler ( (XIOErrorHandler
)X11SalData::XIOErrorHdl
);
466 SalDisplay
*pSalDisplay
= new SalX11Display( pDisp
);
468 pInputMethod
->CreateMethod( pDisp
);
469 pInputMethod
->AddConnectionWatch( pDisp
, (void*)this );
470 pSalDisplay
->SetInputMethod( pInputMethod
);
472 PushXErrorLevel( true );
473 SalI18N_KeyboardExtension
*pKbdExtension
= new SalI18N_KeyboardExtension( pDisp
);
474 XSync( pDisp
, False
);
476 pKbdExtension
->UseExtension( ! HasXErrorOccured() );
479 pSalDisplay
->SetKbdExtension( pKbdExtension
);
483 void EmitFontpathWarning( void )
485 static Bool bOnce
= False
;
489 std::fprintf( stderr
, "Please verify your fontpath settings\n"
490 "\t(See \"man xset\" for details"
491 " or ask your system administrator)\n" );
497 static void PrintXError( Display
*pDisplay
, XErrorEvent
*pEvent
)
499 char msg
[ 120 ] = "";
500 #if ! ( defined LINUX && defined PPC )
501 XGetErrorText( pDisplay
, pEvent
->error_code
, msg
, sizeof( msg
) );
503 std::fprintf( stderr
, "X-Error: %s\n", msg
);
504 if( pEvent
->request_code
< capacityof( XRequest
) )
506 const char* pName
= XRequest
[pEvent
->request_code
];
508 pName
= "BadRequest?";
509 std::fprintf( stderr
, "\tMajor opcode: %d (%s)\n", pEvent
->request_code
, pName
);
513 std::fprintf( stderr
, "\tMajor opcode: %d\n", pEvent
->request_code
);
514 // TODO: also display extension name?
515 std::fprintf( stderr
, "\tMinor opcode: %d\n", pEvent
->minor_code
);
518 std::fprintf( stderr
, "\tResource ID: 0x%lx\n",
519 pEvent
->resourceid
);
520 std::fprintf( stderr
, "\tSerial No: %ld (%ld)\n",
521 pEvent
->serial
, LastKnownRequestProcessed(pDisplay
) );
523 if( !getenv( "SAL_SYNCHRONIZE" ) )
525 std::fprintf( stderr
, "These errors are reported asynchronously,\n");
526 std::fprintf( stderr
, "set environment variable SAL_SYNCHRONIZE to 1 to help debugging\n");
529 std::fflush( stdout
);
530 std::fflush( stderr
);
533 void SalXLib::XError( Display
*pDisplay
, XErrorEvent
*pEvent
)
535 if( m_bHaveSystemChildFrames
)
538 if( ! m_aXErrorHandlerStack
.back().m_bIgnore
)
540 if ( (pEvent
->error_code
== BadAlloc
)
541 && (pEvent
->request_code
== X_OpenFont
) )
543 static Bool bOnce
= False
;
546 std::fprintf(stderr
, "X-Error occured in a request for X_OpenFont\n");
547 EmitFontpathWarning();
554 * X_SetInputFocus: it's a hint only anyway
555 * X_GetProperty: this is part of the XGetWindowProperty call and will
556 * be handled by the return value of that function
558 else if( pEvent
->request_code
== X_SetInputFocus
||
559 pEvent
->request_code
== X_GetProperty
564 if( pDisplay
!= GetX11SalData()->GetDisplay()->GetDisplay() )
567 PrintXError( pDisplay
, pEvent
);
569 oslSignalAction eToDo
= osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR
, NULL
);
572 case osl_Signal_ActIgnore
:
574 case osl_Signal_ActAbortApp
:
576 case osl_Signal_ActKillApp
:
578 case osl_Signal_ActCallNextHdl
:
586 m_aXErrorHandlerStack
.back().m_bWas
= true;
591 YieldEntry
* next
; // pointer to next entry
592 int fd
; // file descriptor for reading
593 void* data
; // data for predicate and callback
594 YieldFunc pending
; // predicate (determins pending events)
595 YieldFunc queued
; // read and queue up events
596 YieldFunc handle
; // handle pending events
598 inline int HasPendingEvent() const { return pending( fd
, data
); }
599 inline int IsEventQueued() const { return queued( fd
, data
); }
600 inline void HandleNextEvent() const { handle( fd
, data
); }
603 #define MAX_NUM_DESCRIPTORS 128
605 static YieldEntry yieldTable
[ MAX_NUM_DESCRIPTORS
];
607 void SalXLib::Insert( int nFD
, void* data
,
612 DBG_ASSERT( nFD
, "can not insert stdin descriptor" );
613 DBG_ASSERT( !yieldTable
[nFD
].fd
, "SalXLib::Insert fd twice" );
615 yieldTable
[nFD
].fd
= nFD
;
616 yieldTable
[nFD
].data
= data
;
617 yieldTable
[nFD
].pending
= pending
;
618 yieldTable
[nFD
].queued
= queued
;
619 yieldTable
[nFD
].handle
= handle
;
621 FD_SET( nFD
, &aReadFDS_
);
622 FD_SET( nFD
, &aExceptionFDS_
);
628 void SalXLib::Remove( int nFD
)
630 FD_CLR( nFD
, &aReadFDS_
);
631 FD_CLR( nFD
, &aExceptionFDS_
);
633 yieldTable
[nFD
].fd
= 0;
637 for ( nFD
= nFDs_
- 1;
638 nFD
>= 0 && !yieldTable
[nFD
].fd
;
645 bool SalXLib::CheckTimeout( bool bExecuteTimers
)
648 if( m_aTimeout
.tv_sec
) // timer is started
651 gettimeofday( &aTimeOfDay
, 0 );
652 if( aTimeOfDay
>= m_aTimeout
)
657 // timed out, update timeout
658 m_aTimeout
= aTimeOfDay
;
660 * #107827# autorestart immediately, will be stopped (or set
661 * to different value in notify hdl if necessary;
662 * CheckTimeout should return false while
663 * timers are being dispatched.
665 m_aTimeout
+= m_nTimeoutMS
;
667 GetX11SalData()->Timeout();
674 void SalXLib::Yield( bool bWait
, bool bHandleAllCurrentEvents
)
676 // check for timeouts here if you want to make screenshots
677 static char* p_prioritize_timer
= getenv ("SAL_HIGHPRIORITY_REPAINT");
678 if (p_prioritize_timer
!= NULL
)
681 // first, check for already queued events.
682 for ( int nFD
= 0; nFD
< nFDs_
; nFD
++ )
684 YieldEntry
* pEntry
= &(yieldTable
[nFD
]);
687 DBG_ASSERT( nFD
== pEntry
->fd
, "wrong fd in Yield()" );
688 if ( pEntry
->HasPendingEvent() )
690 pEntry
->HandleNextEvent();
691 // #63862# da jetzt alle user-events ueber die interne
692 // queue kommen, wird die Kontrolle analog zum select
693 // gesteuerten Zweig einmal bei bWait abgegeben
695 /* #i9277# do not reschedule since performance gets down the
696 the drain under heavy load
697 YieldMutexReleaser aReleaser;
698 if ( bWait ) osl_yieldThread();
706 // next, select with or without timeout according to bWait.
708 fd_set ReadFDS
= aReadFDS_
;
709 fd_set ExceptionFDS
= aExceptionFDS_
;
712 timeval Timeout
= noyield__
;
713 timeval
*pTimeout
= &Timeout
;
718 if (m_aTimeout
.tv_sec
) // Timer is started.
720 // determine remaining timeout.
721 gettimeofday (&Timeout
, 0);
722 Timeout
= m_aTimeout
- Timeout
;
723 if (yield__
>= Timeout
)
725 // guard against micro timeout.
733 // release YieldMutex (and re-acquire at block end)
734 YieldMutexReleaser aReleaser
;
735 nFound
= select( nFDs
, &ReadFDS
, NULL
, &ExceptionFDS
, pTimeout
);
737 if( nFound
< 0 ) // error
740 std::fprintf( stderr
, "SalXLib::Yield e=%d f=%d\n", errno
, nFound
);
748 // usually handle timeouts here (as in 5.2)
749 if (p_prioritize_timer
== NULL
)
752 // handle wakeup events.
753 if ((nFound
> 0) && (FD_ISSET(m_pTimeoutFDS
[0], &ReadFDS
)))
756 while (read (m_pTimeoutFDS
[0], &buffer
, sizeof(buffer
)) > 0)
761 // handle other events.
764 // now we are in the protected section !
765 // recall select if we have acquired fd's, ready for reading,
767 struct timeval noTimeout
= { 0, 0 };
768 nFound
= select( nFDs_
, &ReadFDS
, NULL
,
769 &ExceptionFDS
, &noTimeout
);
771 // someone-else has done the job for us
775 for ( int nFD
= 0; nFD
< nFDs_
; nFD
++ )
777 YieldEntry
* pEntry
= &(yieldTable
[nFD
]);
780 if ( FD_ISSET( nFD
, &ExceptionFDS
) ) {
781 #if OSL_DEBUG_LEVEL > 1
782 std::fprintf( stderr
, "SalXLib::Yield exception\n" );
786 if ( FD_ISSET( nFD
, &ReadFDS
) )
788 int nMaxEvents
= bHandleAllCurrentEvents
? 100 : 1;
789 for( int i
= 0; pEntry
->IsEventQueued() && i
< nMaxEvents
; i
++ )
791 pEntry
->HandleNextEvent();
792 // if a recursive call has done the job
802 void SalXLib::Wakeup()
804 write (m_pTimeoutFDS
[1], "", 1);
807 void SalXLib::PostUserEvent()
812 const char* X11SalData::getFrameResName()
814 /* according to ICCCM:
815 * first search command line for -name parameter
816 * then try RESOURCE_NAME environment variable
817 * then use argv[0] stripped by directories
819 static rtl::OStringBuffer aResName
;
820 if( !aResName
.getLength() )
822 int nArgs
= osl_getCommandArgCount();
823 for( int n
= 0; n
< nArgs
-1; n
++ )
826 if( ! osl_getCommandArg( n
, &aArg
.pData
) &&
827 aArg
.equalsIgnoreAsciiCaseAscii( "-name" ) &&
828 ! osl_getCommandArg( n
+1, &aArg
.pData
) )
830 aResName
.append( rtl::OUStringToOString( aArg
, osl_getThreadTextEncoding() ) );
834 if( !aResName
.getLength() )
836 const char* pEnv
= getenv( "RESOURCE_NAME" );
838 aResName
.append( pEnv
);
840 if( !aResName
.getLength() )
841 aResName
.append( "VCLSalFrame" );
843 return aResName
.getStr();
846 const char* X11SalData::getFrameClassName()
848 static rtl::OStringBuffer aClassName
;
849 if( !aClassName
.getLength() )
851 rtl::OUString aIni
, aProduct
;
852 rtl::Bootstrap::get( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "BRAND_BASE_DIR" ) ), aIni
);
853 aIni
+= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/program/" SAL_CONFIGFILE( "bootstrap" ) ) );
854 rtl::Bootstrap
aBootstrap( aIni
);
855 aBootstrap
.getFrom( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ProductKey" ) ), aProduct
);
857 if( aProduct
.getLength() )
858 aClassName
.append( rtl::OUStringToOString( aProduct
, osl_getThreadTextEncoding() ) );
860 aClassName
.append( "VCLSalFrame" );
862 return aClassName
.getStr();
865 rtl::OString
X11SalData::getFrameResName( SalExtStyle nStyle
)
867 rtl::OStringBuffer
aBuf( 64 );
868 aBuf
.append( getFrameResName() );
869 if( (nStyle
& SAL_FRAME_EXT_STYLE_DOCUMENT
) )
870 aBuf
.append( ".DocumentWindow" );
872 return aBuf
.makeStringAndClear();