1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <unistd.h>
21 #include <fcntl.h>
22 
23 #include <cstdio>
24 #include <cstdlib>
25 #include <errno.h>
26 #ifdef SUN
27 #include <sys/systeminfo.h>
28 #endif
29 #ifdef AIX
30 #include <strings.h>
31 #endif
32 #ifdef DRAGONFLY
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #endif
36 
37 #include <osl/process.h>
38 
39 #include <unx/saldisp.hxx>
40 #include <unx/saldata.hxx>
41 #include <unx/salunxtime.h>
42 #include <unx/sm.hxx>
43 #include <unx/i18n_im.hxx>
44 
45 #include <X11/Xlib.h>
46 #include <X11/Xproto.h>
47 
48 #include <salinst.hxx>
49 #include <saltimer.hxx>
50 
51 #include <osl/diagnose.h>
52 #include <osl/signal.h>
53 #include <osl/thread.h>
54 #include <sal/log.hxx>
55 
56 #include <vcl/svapp.hxx>
57 
GetX11SalData()58 X11SalData* GetX11SalData()
59 {
60     SalData * p1 = ImplGetSVData()->mpSalData;
61     OSL_ASSERT(p1 != nullptr);
62     X11SalData * p2 = dynamic_cast< X11SalData * >(p1);
63     OSL_ASSERT(p2 != nullptr);
64     return p2;
65 }
66 
67 extern "C" {
68 
XErrorHdl(Display * pDisplay,XErrorEvent * pEvent)69 static int XErrorHdl( Display *pDisplay, XErrorEvent *pEvent )
70 {
71     GetX11SalData()->XError( pDisplay, pEvent );
72     return 0;
73 }
74 
XIOErrorHdl(Display *)75 static int XIOErrorHdl( Display * )
76 {
77     if ( Application::IsMainThread() )
78     {
79         /*  #106197# hack: until a real shutdown procedure exists
80          *  _exit ASAP
81          */
82         if( ImplGetSVData()->maAppData.mbAppQuit )
83             _exit(1);
84 
85         // really bad hack
86         if( ! SessionManagerClient::checkDocumentsSaved() )
87             /* oslSignalAction eToDo = */ osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, nullptr);
88     }
89 
90     std::fprintf( stderr, "X IO Error\n" );
91     std::fflush( stdout );
92     std::fflush( stderr );
93 
94     /*  #106197# the same reasons to use _exit instead of exit in salmain
95      *  do apply here. Since there is nothing to be done after an XIO
96      *  error we have to _exit immediately.
97      */
98     _exit(1);
99     return 0;
100 }
101 
102 }
103 
104 const struct timeval noyield_ = { 0, 0 };
105 const struct timeval yield_   = { 0, 10000 };
106 
107 static const char* XRequest[] = {
108     // see /usr/lib/X11/XErrorDB, /usr/openwin/lib/XErrorDB ...
109     nullptr,
110     "X_CreateWindow",
111     "X_ChangeWindowAttributes",
112     "X_GetWindowAttributes",
113     "X_DestroyWindow",
114     "X_DestroySubwindows",
115     "X_ChangeSaveSet",
116     "X_ReparentWindow",
117     "X_MapWindow",
118     "X_MapSubwindows",
119     "X_UnmapWindow",
120     "X_UnmapSubwindows",
121     "X_ConfigureWindow",
122     "X_CirculateWindow",
123     "X_GetGeometry",
124     "X_QueryTree",
125     "X_InternAtom",
126     "X_GetAtomName",
127     "X_ChangeProperty",
128     "X_DeleteProperty",
129     "X_GetProperty",
130     "X_ListProperties",
131     "X_SetSelectionOwner",
132     "X_GetSelectionOwner",
133     "X_ConvertSelection",
134     "X_SendEvent",
135     "X_GrabPointer",
136     "X_UngrabPointer",
137     "X_GrabButton",
138     "X_UngrabButton",
139     "X_ChangeActivePointerGrab",
140     "X_GrabKeyboard",
141     "X_UngrabKeyboard",
142     "X_GrabKey",
143     "X_UngrabKey",
144     "X_AllowEvents",
145     "X_GrabServer",
146     "X_UngrabServer",
147     "X_QueryPointer",
148     "X_GetMotionEvents",
149     "X_TranslateCoords",
150     "X_WarpPointer",
151     "X_SetInputFocus",
152     "X_GetInputFocus",
153     "X_QueryKeymap",
154     "X_OpenFont",
155     "X_CloseFont",
156     "X_QueryFont",
157     "X_QueryTextExtents",
158     "X_ListFonts",
159     "X_ListFontsWithInfo",
160     "X_SetFontPath",
161     "X_GetFontPath",
162     "X_CreatePixmap",
163     "X_FreePixmap",
164     "X_CreateGC",
165     "X_ChangeGC",
166     "X_CopyGC",
167     "X_SetDashes",
168     "X_SetClipRectangles",
169     "X_FreeGC",
170     "X_ClearArea",
171     "X_CopyArea",
172     "X_CopyPlane",
173     "X_PolyPoint",
174     "X_PolyLine",
175     "X_PolySegment",
176     "X_PolyRectangle",
177     "X_PolyArc",
178     "X_FillPoly",
179     "X_PolyFillRectangle",
180     "X_PolyFillArc",
181     "X_PutImage",
182     "X_GetImage",
183     "X_PolyText8",
184     "X_PolyText16",
185     "X_ImageText8",
186     "X_ImageText16",
187     "X_CreateColormap",
188     "X_FreeColormap",
189     "X_CopyColormapAndFree",
190     "X_InstallColormap",
191     "X_UninstallColormap",
192     "X_ListInstalledColormaps",
193     "X_AllocColor",
194     "X_AllocNamedColor",
195     "X_AllocColorCells",
196     "X_AllocColorPlanes",
197     "X_FreeColors",
198     "X_StoreColors",
199     "X_StoreNamedColor",
200     "X_QueryColors",
201     "X_LookupColor",
202     "X_CreateCursor",
203     "X_CreateGlyphCursor",
204     "X_FreeCursor",
205     "X_RecolorCursor",
206     "X_QueryBestSize",
207     "X_QueryExtension",
208     "X_ListExtensions",
209     "X_ChangeKeyboardMapping",
210     "X_GetKeyboardMapping",
211     "X_ChangeKeyboardControl",
212     "X_GetKeyboardControl",
213     "X_Bell",
214     "X_ChangePointerControl",
215     "X_GetPointerControl",
216     "X_SetScreenSaver",
217     "X_GetScreenSaver",
218     "X_ChangeHosts",
219     "X_ListHosts",
220     "X_SetAccessControl",
221     "X_SetCloseDownMode",
222     "X_KillClient",
223     "X_RotateProperties",
224     "X_ForceScreenSaver",
225     "X_SetPointerMapping",
226     "X_GetPointerMapping",
227     "X_SetModifierMapping",
228     "X_GetModifierMapping",
229     nullptr,
230     nullptr,
231     nullptr,
232     nullptr,
233     nullptr,
234     nullptr,
235     nullptr,
236     "X_NoOperation"
237 };
238 
X11SalData(GenericUnixSalDataType t,SalInstance * pInstance)239 X11SalData::X11SalData( GenericUnixSalDataType t, SalInstance *pInstance )
240     : GenericUnixSalData( t, pInstance )
241 {
242     pXLib_          = nullptr;
243 
244     m_aOrigXIOErrorHandler = XSetIOErrorHandler ( XIOErrorHdl );
245     PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
246 }
247 
~X11SalData()248 X11SalData::~X11SalData()
249 {
250     DeleteDisplay();
251     PopXErrorLevel();
252     XSetIOErrorHandler (m_aOrigXIOErrorHandler);
253 }
254 
Dispose()255 void X11SalData::Dispose()
256 {
257     delete GetDisplay();
258     SetSalData( nullptr );
259 }
260 
DeleteDisplay()261 void X11SalData::DeleteDisplay()
262 {
263     delete GetDisplay();
264     SetDisplay( nullptr );
265     pXLib_.reset();
266 }
267 
Init()268 void X11SalData::Init()
269 {
270     pXLib_.reset(new SalXLib());
271     pXLib_->Init();
272 }
273 
ErrorTrapPush()274 void X11SalData::ErrorTrapPush()
275 {
276     PushXErrorLevel( true );
277 }
278 
ErrorTrapPop(bool bIgnoreError)279 bool X11SalData::ErrorTrapPop( bool bIgnoreError )
280 {
281     bool err = false;
282     if( !bIgnoreError )
283         err = HasXErrorOccurred();
284     ResetXErrorOccurred();
285     PopXErrorLevel();
286     return err;
287 }
288 
PushXErrorLevel(bool bIgnore)289 void X11SalData::PushXErrorLevel( bool bIgnore )
290 {
291     m_aXErrorHandlerStack.emplace_back( );
292     XErrorStackEntry& rEnt = m_aXErrorHandlerStack.back();
293     rEnt.m_bWas = false;
294     rEnt.m_bIgnore = bIgnore;
295     rEnt.m_aHandler = XSetErrorHandler( XErrorHdl );
296 }
297 
PopXErrorLevel()298 void X11SalData::PopXErrorLevel()
299 {
300     if( !m_aXErrorHandlerStack.empty() )
301     {
302         XSetErrorHandler( m_aXErrorHandlerStack.back().m_aHandler );
303         m_aXErrorHandlerStack.pop_back();
304     }
305 }
306 
SalXLib()307 SalXLib::SalXLib()
308 {
309     m_aTimeout.tv_sec       = 0;
310     m_aTimeout.tv_usec      = 0;
311     m_nTimeoutMS            = 0;
312 
313     nFDs_                   = 0;
314     FD_ZERO( &aReadFDS_ );
315     FD_ZERO( &aExceptionFDS_ );
316 
317     m_pInputMethod          = nullptr;
318     m_pDisplay              = nullptr;
319 
320     m_pTimeoutFDS[0] = m_pTimeoutFDS[1] = -1;
321     if (pipe (m_pTimeoutFDS) == -1)
322         return;
323 
324     // initialize 'wakeup' pipe.
325     int flags;
326 
327     // set close-on-exec descriptor flag.
328     if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFD)) != -1)
329     {
330         flags |= FD_CLOEXEC;
331         (void)fcntl(m_pTimeoutFDS[0], F_SETFD, flags);
332     }
333     if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFD)) != -1)
334     {
335         flags |= FD_CLOEXEC;
336         (void)fcntl(m_pTimeoutFDS[1], F_SETFD, flags);
337     }
338 
339     // set non-blocking I/O flag.
340     if ((flags = fcntl (m_pTimeoutFDS[0], F_GETFL)) != -1)
341     {
342         flags |= O_NONBLOCK;
343         (void)fcntl(m_pTimeoutFDS[0], F_SETFL, flags);
344     }
345     if ((flags = fcntl (m_pTimeoutFDS[1], F_GETFL)) != -1)
346     {
347         flags |= O_NONBLOCK;
348         (void)fcntl(m_pTimeoutFDS[1], F_SETFL, flags);
349     }
350 
351     // insert [0] into read descriptor set.
352     FD_SET( m_pTimeoutFDS[0], &aReadFDS_ );
353     nFDs_ = m_pTimeoutFDS[0] + 1;
354 }
355 
~SalXLib()356 SalXLib::~SalXLib()
357 {
358     // close 'wakeup' pipe.
359     close (m_pTimeoutFDS[0]);
360     close (m_pTimeoutFDS[1]);
361 
362     m_pInputMethod.reset();
363 }
364 
OpenX11Display(OString & rDisplay)365 static Display *OpenX11Display(OString& rDisplay)
366 {
367     /*
368      * open connection to X11 Display
369      * try in this order:
370      *  o  -display command line parameter,
371      *  o  $DISPLAY environment variable
372      *  o  default display
373      */
374 
375     Display *pDisp = nullptr;
376 
377     // is there a -display command line parameter?
378 
379     sal_uInt32 nParams = osl_getCommandArgCount();
380     OUString aParam;
381     for (sal_uInt32 i=0; i<nParams; i++)
382     {
383         osl_getCommandArg(i, &aParam.pData);
384         if ( aParam == "-display" )
385         {
386             osl_getCommandArg(i+1, &aParam.pData);
387             rDisplay = OUStringToOString(
388                    aParam, osl_getThreadTextEncoding());
389 
390             if ((pDisp = XOpenDisplay(rDisplay.getStr()))!=nullptr)
391             {
392                 /*
393                  * if a -display switch was used, we need
394                  * to set the environment accordingly since
395                  * the clipboard build another connection
396                  * to the xserver using $DISPLAY
397                  */
398                 OUString envVar("DISPLAY");
399                 osl_setEnvironment(envVar.pData, aParam.pData);
400             }
401             break;
402         }
403     }
404 
405     if (!pDisp && rDisplay.isEmpty())
406     {
407         // Open $DISPLAY or default...
408         char *pDisplay = getenv("DISPLAY");
409         if (pDisplay != nullptr)
410             rDisplay = OString(pDisplay);
411         pDisp  = XOpenDisplay(pDisplay);
412     }
413 
414     return pDisp;
415 }
416 
Init()417 void SalXLib::Init()
418 {
419     m_pInputMethod.reset( new SalI18N_InputMethod );
420     m_pInputMethod->SetLocale();
421     XrmInitialize();
422 
423     OString aDisplay;
424     m_pDisplay = OpenX11Display(aDisplay);
425 
426     if ( m_pDisplay )
427         return;
428 
429     OUString aProgramFileURL;
430     osl_getExecutableFile( &aProgramFileURL.pData );
431     OUString aProgramSystemPath;
432     osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
433     OString  aProgramName = OUStringToOString(
434                                         aProgramSystemPath,
435                                         osl_getThreadTextEncoding() );
436     std::fprintf( stderr, "%s X11 error: Can't open display: %s\n",
437             aProgramName.getStr(), aDisplay.getStr());
438     std::fprintf( stderr, "   Set DISPLAY environment variable, use -display option\n");
439     std::fprintf( stderr, "   or check permissions of your X-Server\n");
440     std::fprintf( stderr, "   (See \"man X\" resp. \"man xhost\" for details)\n");
441     std::fflush( stderr );
442     exit(0);
443 
444 }
445 
446 extern "C" {
EmitFontpathWarning()447 static void EmitFontpathWarning()
448 {
449     static Bool bOnce = False;
450     if ( !bOnce )
451     {
452         bOnce = True;
453         std::fprintf( stderr, "Please verify your fontpath settings\n"
454                 "\t(See \"man xset\" for details"
455                 " or ask your system administrator)\n" );
456     }
457 }
458 
459 } /* extern "C" */
460 
PrintXError(Display * pDisplay,XErrorEvent * pEvent)461 static void PrintXError( Display *pDisplay, XErrorEvent *pEvent )
462 {
463     char msg[ 120 ] = "";
464     XGetErrorText( pDisplay, pEvent->error_code, msg, sizeof( msg ) );
465     std::fprintf( stderr, "X-Error: %s\n", msg );
466     if( pEvent->request_code < SAL_N_ELEMENTS( XRequest ) )
467     {
468         const char* pName = XRequest[pEvent->request_code];
469         if( !pName )
470             pName = "BadRequest?";
471         std::fprintf( stderr, "\tMajor opcode: %d (%s)\n", pEvent->request_code, pName );
472     }
473     else
474     {
475         std::fprintf( stderr, "\tMajor opcode: %d\n", pEvent->request_code );
476         // TODO: also display extension name?
477         std::fprintf( stderr, "\tMinor opcode: %d\n", pEvent->minor_code );
478     }
479 
480     std::fprintf( stderr, "\tResource ID:  0x%lx\n",
481              pEvent->resourceid );
482     std::fprintf( stderr, "\tSerial No:    %ld (%ld)\n",
483              pEvent->serial, LastKnownRequestProcessed(pDisplay) );
484 
485     if( !getenv( "SAL_SYNCHRONIZE" ) )
486     {
487         std::fprintf( stderr, "These errors are reported asynchronously,\n");
488         std::fprintf( stderr, "set environment variable SAL_SYNCHRONIZE to 1 to help debugging\n");
489     }
490 
491     std::fflush( stdout );
492     std::fflush( stderr );
493 }
494 
XError(Display * pDisplay,XErrorEvent * pEvent)495 void X11SalData::XError( Display *pDisplay, XErrorEvent *pEvent )
496 {
497     if( ! m_aXErrorHandlerStack.back().m_bIgnore )
498     {
499         if (   (pEvent->error_code   == BadAlloc)
500             && (pEvent->request_code == X_OpenFont) )
501         {
502             static Bool bOnce = False;
503             if ( !bOnce )
504             {
505                 std::fprintf(stderr, "X-Error occurred in a request for X_OpenFont\n");
506                 EmitFontpathWarning();
507 
508                 bOnce = True ;
509             }
510             return;
511         }
512         /* ignore
513         * X_SetInputFocus: it's a hint only anyway
514         * X_GetProperty: this is part of the XGetWindowProperty call and will
515         *                be handled by the return value of that function
516         */
517         else if( pEvent->request_code == X_SetInputFocus ||
518                  pEvent->request_code == X_GetProperty
519             )
520             return;
521 
522         if( pDisplay != vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay() )
523             return;
524 
525         PrintXError( pDisplay, pEvent );
526 
527         oslSignalAction eToDo = osl_raiseSignal (OSL_SIGNAL_USER_X11SUBSYSTEMERROR, nullptr);
528         switch (eToDo)
529         {
530             case osl_Signal_ActIgnore       :
531                 return;
532             case osl_Signal_ActAbortApp     :
533                 abort();
534             case osl_Signal_ActKillApp      :
535                 exit(0);
536             case osl_Signal_ActCallNextHdl  :
537                 break;
538             default :
539                 break;
540         }
541 
542     }
543 
544     m_aXErrorHandlerStack.back().m_bWas = true;
545 }
546 
Timeout()547 void X11SalData::Timeout()
548 {
549     ImplSVData* pSVData = ImplGetSVData();
550     if( pSVData->maSchedCtx.mpSalTimer )
551         pSVData->maSchedCtx.mpSalTimer->CallCallback();
552 }
553 
554 namespace {
555 
556 struct YieldEntry
557 {
558     int         fd;         // file descriptor for reading
559     void*           data;       // data for predicate and callback
560     YieldFunc       pending;    // predicate (determines pending events)
561     YieldFunc       queued;     // read and queue up events
562     YieldFunc       handle;     // handle pending events
563 
HasPendingEvent__anon3c44f8c20111::YieldEntry564     int  HasPendingEvent()   const { return pending( fd, data ); }
IsEventQueued__anon3c44f8c20111::YieldEntry565     int  IsEventQueued()     const { return queued( fd, data ); }
HandleNextEvent__anon3c44f8c20111::YieldEntry566     void HandleNextEvent()   const { handle( fd, data ); }
567 };
568 
569 }
570 
571 #define MAX_NUM_DESCRIPTORS 128
572 
573 static YieldEntry yieldTable[ MAX_NUM_DESCRIPTORS ];
574 
Insert(int nFD,void * data,YieldFunc pending,YieldFunc queued,YieldFunc handle)575 void SalXLib::Insert( int nFD, void* data,
576                       YieldFunc     pending,
577                       YieldFunc     queued,
578                       YieldFunc     handle )
579 {
580     SAL_WARN_IF( !nFD, "vcl", "can not insert stdin descriptor" );
581     SAL_WARN_IF( yieldTable[nFD].fd, "vcl", "SalXLib::Insert fd twice" );
582 
583     yieldTable[nFD].fd      = nFD;
584     yieldTable[nFD].data    = data;
585     yieldTable[nFD].pending = pending;
586     yieldTable[nFD].queued  = queued;
587     yieldTable[nFD].handle  = handle;
588 
589     FD_SET( nFD, &aReadFDS_ );
590     FD_SET( nFD, &aExceptionFDS_ );
591 
592     if( nFD >= nFDs_ )
593         nFDs_ = nFD + 1;
594 }
595 
Remove(int nFD)596 void SalXLib::Remove( int nFD )
597 {
598     FD_CLR( nFD, &aReadFDS_ );
599     FD_CLR( nFD, &aExceptionFDS_ );
600 
601     yieldTable[nFD].fd = 0;
602 
603     if ( nFD == nFDs_ )
604     {
605         for ( nFD = nFDs_ - 1;
606               nFD >= 0 && !yieldTable[nFD].fd;
607               nFD-- ) ;
608 
609         nFDs_ = nFD + 1;
610     }
611 }
612 
CheckTimeout(bool bExecuteTimers)613 bool SalXLib::CheckTimeout( bool bExecuteTimers )
614 {
615     bool bRet = false;
616     if( m_aTimeout.tv_sec ) // timer is started
617     {
618         timeval aTimeOfDay;
619         gettimeofday( &aTimeOfDay, nullptr );
620         if( aTimeOfDay >= m_aTimeout )
621         {
622             bRet = true;
623             if( bExecuteTimers )
624             {
625                 // timed out, update timeout
626                 m_aTimeout = aTimeOfDay;
627                 /*
628                 *  #107827# autorestart immediately, will be stopped (or set
629                 *  to different value in notify hdl if necessary;
630                 *  CheckTimeout should return false while
631                 *  timers are being dispatched.
632                 */
633                 m_aTimeout += m_nTimeoutMS;
634                 // notify
635                 X11SalData::Timeout();
636             }
637         }
638     }
639     return bRet;
640 }
641 
642 bool
Yield(bool bWait,bool bHandleAllCurrentEvents)643 SalXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
644 {
645     // check for timeouts here if you want to make screenshots
646     static char* p_prioritize_timer = getenv ("SAL_HIGHPRIORITY_REPAINT");
647     bool bHandledEvent = false;
648     if (p_prioritize_timer != nullptr)
649         bHandledEvent = CheckTimeout();
650 
651     const int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
652 
653     // first, check for already queued events.
654     for ( int nFD = 0; nFD < nFDs_; nFD++ )
655     {
656         YieldEntry* pEntry = &(yieldTable[nFD]);
657         if ( pEntry->fd )
658         {
659             SAL_WARN_IF( nFD != pEntry->fd, "vcl", "wrong fd in Yield()" );
660             for( int i = 0; i < nMaxEvents && pEntry->HasPendingEvent(); i++ )
661             {
662                 pEntry->HandleNextEvent();
663                 if( ! bHandleAllCurrentEvents )
664                 {
665                     return true;
666                 }
667             }
668         }
669     }
670 
671     // next, select with or without timeout according to bWait.
672     int      nFDs         = nFDs_;
673     fd_set   ReadFDS      = aReadFDS_;
674     fd_set   ExceptionFDS = aExceptionFDS_;
675     int      nFound       = 0;
676 
677     timeval  Timeout      = noyield_;
678     timeval *pTimeout     = &Timeout;
679 
680 
681     if (bWait)
682     {
683         pTimeout = nullptr;
684         if (m_aTimeout.tv_sec) // Timer is started.
685         {
686             // determine remaining timeout.
687             gettimeofday (&Timeout, nullptr);
688             Timeout = m_aTimeout - Timeout;
689             if (yield_ >= Timeout)
690             {
691                 // guard against micro timeout.
692                 Timeout = yield_;
693             }
694             pTimeout = &Timeout;
695         }
696     }
697 
698     {
699         // release YieldMutex (and re-acquire at block end)
700         SolarMutexReleaser aReleaser;
701         nFound = select( nFDs, &ReadFDS, nullptr, &ExceptionFDS, pTimeout );
702     }
703     if( nFound < 0 ) // error
704     {
705 #ifdef DBG_UTIL
706         SAL_INFO("vcl.app", "SalXLib::Yield e=" << errno << " f=" << nFound);
707 #endif
708         if( EINTR == errno )
709         {
710             errno = 0;
711         }
712     }
713 
714     // usually handle timeouts here (as in 5.2)
715     if (p_prioritize_timer == nullptr)
716         bHandledEvent = CheckTimeout() || bHandledEvent;
717 
718     // handle wakeup events.
719     if ((nFound > 0) && FD_ISSET(m_pTimeoutFDS[0], &ReadFDS))
720     {
721         int buffer;
722         while (read (m_pTimeoutFDS[0], &buffer, sizeof(buffer)) > 0)
723             continue;
724         nFound -= 1;
725     }
726 
727     // handle other events.
728     if( nFound > 0 )
729     {
730         // now we are in the protected section !
731         // recall select if we have acquired fd's, ready for reading,
732 
733         struct timeval noTimeout = { 0, 0 };
734         nFound = select( nFDs_, &ReadFDS, nullptr,
735                          &ExceptionFDS, &noTimeout );
736 
737         // someone-else has done the job for us
738         if (nFound == 0)
739         {
740             return false;
741         }
742 
743         for ( int nFD = 0; nFD < nFDs_; nFD++ )
744         {
745             YieldEntry* pEntry = &(yieldTable[nFD]);
746             if ( pEntry->fd )
747             {
748                 if ( FD_ISSET( nFD, &ExceptionFDS ) ) {
749 #if OSL_DEBUG_LEVEL > 1
750                     SAL_WARN("vcl.app", "SalXLib::Yield exception.");
751 #endif
752                     nFound--;
753                 }
754                 if ( FD_ISSET( nFD, &ReadFDS ) )
755                 {
756                     for( int i = 0; pEntry->IsEventQueued() && i < nMaxEvents; i++ )
757                     {
758                         pEntry->HandleNextEvent();
759                         bHandledEvent = true;
760                         // if a recursive call has done the job
761                         // so abort here
762                     }
763                     nFound--;
764                 }
765             }
766         }
767     }
768 
769     return bHandledEvent;
770 }
771 
Wakeup()772 void SalXLib::Wakeup()
773 {
774     OSL_VERIFY(write (m_pTimeoutFDS[1], "", 1) == 1);
775 }
776 
TriggerUserEventProcessing()777 void SalXLib::TriggerUserEventProcessing()
778 {
779     Wakeup();
780 }
781 
782 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
783