xref: /trunk/main/vcl/unx/gtk/app/gtkdata.cxx (revision e1397ed79746b1482a549a3b8499549cff06c5f4)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_vcl.hxx"
24 
25 #define _SV_SALDATA_CXX
26 
27 // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
28 
29 #include <unistd.h>
30 #include <fcntl.h>
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <limits.h>
36 #include <errno.h>
37 #include <poll.h>
38 #ifdef FREEBSD
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <unistd.h>
42 #endif
43 #include <unx/gtk/gtkdata.hxx>
44 #include <unx/gtk/gtkinst.hxx>
45 #include <unx/gtk/gtkframe.hxx>
46 #include <unx/salobj.h>
47 #include <osl/thread.h>
48 #include <osl/process.h>
49 
50 #include <tools/debug.hxx>
51 #include "unx/i18n_im.hxx"
52 #include "unx/i18n_xkb.hxx"
53 #include <unx/wmadaptor.hxx>
54 
55 #include "unx/x11_cursors/salcursors.h"
56 
57 #include <vcl/svapp.hxx>
58 
59 using namespace rtl;
60 using namespace vcl_sal;
61 
62 /***************************************************************************
63  * class GtkDisplay
64  ***************************************************************************/
65 
GtkSalDisplay(GdkDisplay * pDisplay)66 GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay )
67             : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ),
68               m_pGdkDisplay( pDisplay ),
69               m_bStartupCompleted( false )
70 {
71     m_bUseRandRWrapper = false; // use gdk signal instead
72     for(int i = 0; i < POINTER_COUNT; i++)
73         m_aCursors[ i ] = NULL;
74     Init ();
75 }
76 
~GtkSalDisplay()77 GtkSalDisplay::~GtkSalDisplay()
78 {
79     if( !m_bStartupCompleted )
80         gdk_notify_startup_complete();
81     doDestruct();
82 
83     for(int i = 0; i < POINTER_COUNT; i++)
84         if( m_aCursors[ i ] )
85             gdk_cursor_unref( m_aCursors[ i ] );
86 
87     pDisp_ = NULL;
88 }
89 
deregisterFrame(SalFrame * pFrame)90 void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
91 {
92     if( m_pCapture == pFrame )
93     {
94         static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
95         m_pCapture = NULL;
96     }
97     for( std::map< XLIB_Window, GtkSalFrame* >::iterator it = m_aWindowFrameMap.begin();
98          it != m_aWindowFrameMap.end(); )
99     {
100         if( it->second == static_cast<GtkSalFrame*>(pFrame) )
101         {
102             std::map< XLIB_Window, GtkSalFrame* >::iterator itNext = it;
103             ++itNext;
104             m_aWindowFrameMap.erase( it );
105             it = itNext;
106         }
107         else
108             ++it;
109     }
110     SalDisplay::deregisterFrame( pFrame );
111 }
112 
113 /*
114  * Each live X11 window ID may be associated with at most one frame.
115  * Window IDs must be deregistered before destruction or reassignment.
116  * Duplicate registration is a lifecycle error and is not overwritten.
117  */
registerFrameWindow(XLIB_Window aWindow,GtkSalFrame * pFrame)118 void GtkSalDisplay::registerFrameWindow( XLIB_Window aWindow, GtkSalFrame* pFrame )
119 {
120     if( aWindow != None && pFrame != NULL )
121     {
122         std::map< XLIB_Window, GtkSalFrame* >::iterator it =
123             m_aWindowFrameMap.find( aWindow );
124 
125         if( it != m_aWindowFrameMap.end() && it->second != pFrame )
126         {
127             OSL_TRACE(
128                 "GtkSalDisplay::registerFrameWindow: refusing duplicate "
129                 "mapping for X window %lu",
130                 static_cast<unsigned long>(aWindow) );
131             return;
132         }
133 
134         m_aWindowFrameMap[ aWindow ] = pFrame;
135     }
136 }
137 
deregisterFrameWindow(XLIB_Window aWindow,GtkSalFrame * pFrame)138 void GtkSalDisplay::deregisterFrameWindow( XLIB_Window aWindow, GtkSalFrame* pFrame )
139 {
140     if( aWindow == None )
141         return;
142     std::map< XLIB_Window, GtkSalFrame* >::iterator it = m_aWindowFrameMap.find( aWindow );
143     if( it != m_aWindowFrameMap.end() )
144     {
145         if( pFrame == NULL || it->second == pFrame )
146             m_aWindowFrameMap.erase( it );
147     }
148 }
149 
findFrameByXWindow(XLIB_Window aWindow) const150 GtkSalFrame* GtkSalDisplay::findFrameByXWindow( XLIB_Window aWindow ) const
151 {
152     if( aWindow == None )
153         return NULL;
154     std::map< XLIB_Window, GtkSalFrame* >::const_iterator it = m_aWindowFrameMap.find( aWindow );
155     if( it != m_aWindowFrameMap.end() )
156         return it->second;
157     return NULL;
158 }
159 
160 extern "C" {
call_filterGdkEvent(GdkXEvent * sys_event,GdkEvent * event,gpointer data)161 GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
162                                      GdkEvent* event,
163                                      gpointer data )
164 {
165     return GtkSalDisplay::filterGdkEvent( sys_event, event, data );
166 }
167 
signalKeysChanged(GdkKeymap *,gpointer data)168 void signalKeysChanged( GdkKeymap*, gpointer data )
169 {
170     GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
171     pDisp->GetKeyboardName(TRUE);
172 }
173 
signalScreenSizeChanged(GdkScreen * pScreen,gpointer data)174 void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
175 {
176     GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
177     pDisp->screenSizeChanged( pScreen );
178 }
179 
signalMonitorsChanged(GdkScreen * pScreen,gpointer data)180 void signalMonitorsChanged( GdkScreen* pScreen, gpointer data )
181 {
182     GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
183     pDisp->monitorsChanged( pScreen );
184 }
185 
186 }
187 
filterGdkEvent(GdkXEvent * sys_event,GdkEvent *,gpointer data)188 GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
189                                                GdkEvent*,
190                                                gpointer data )
191 {
192     GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE;
193 
194     XEvent *pEvent = (XEvent *)sys_event;
195     GtkSalDisplay *pDisplay = (GtkSalDisplay *)data;
196 
197     // dispatch all XEvents to event callback
198     if( GetSalData()->m_pInstance->
199         CallEventCallback( pEvent, sizeof( XEvent ) ) )
200         aFilterReturn = GDK_FILTER_REMOVE;
201 
202     GTK_YIELD_GRAB();
203 
204     if (pDisplay->GetDisplay() == pEvent->xany.display )
205     {
206         // #i53471# gtk has no callback mechanism that lets us be notified
207         // when settings (as in XSETTING and opposed to styles) are changed.
208         // so we need to listen for corresponding property notifications here
209         // these should be rare enough so that we can assume that the settings
210         // actually change when a corresponding PropertyNotify occurs
211         if( pEvent->type == PropertyNotify &&
212             pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) &&
213             ! pDisplay->m_aFrames.empty()
214            )
215         {
216             pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED );
217         }
218         // let's see if one of our frames wants to swallow these events
219         // get the frame
220         GtkSalFrame* pFrame = pDisplay->findFrameByXWindow( pEvent->xany.window );
221         if( pFrame )
222         {
223             if( pFrame->dispatchXEvent( pEvent ) )
224                 aFilterReturn = GDK_FILTER_REMOVE;
225         }
226         X11SalObject::Dispatch( pEvent );
227     }
228 
229     return aFilterReturn;
230 }
231 
screenSizeChanged(GdkScreen * pScreen)232 void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
233 {
234     if( pScreen )
235     {
236         int nScreen = gdk_screen_get_number( pScreen );
237         if( nScreen < static_cast<int>(m_aScreens.size()) )
238         {
239             ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
240             if( rSD.m_bInit )
241             {
242                 rSD.m_aSize = Size( gdk_screen_get_width( pScreen ),
243                                     gdk_screen_get_height( pScreen ) );
244                 if( ! m_aFrames.empty() )
245                     m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
246             }
247         }
248         else
249         {
250             DBG_ERROR( "unknown screen changed size" );
251         }
252     }
253 }
254 
monitorsChanged(GdkScreen * pScreen)255 void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
256 {
257 
258     InitXinerama();
259     (void)pScreen;
260 }
261 
GetDefaultMonitorNumber() const262 int GtkSalDisplay::GetDefaultMonitorNumber() const
263 {
264     // GTK's primary-monitor implementation is disabled; use the
265     // Xinerama default monitor.
266     return 0;
267 }
268 
initScreen(int nScreen) const269 void GtkSalDisplay::initScreen( int nScreen ) const
270 {
271     if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
272         nScreen = m_nDefaultScreen;
273     ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
274     if( rSD.m_bInit )
275         return;
276 
277     // choose visual for screen
278     SalDisplay::initScreen( nScreen );
279     // now set a gdk default colormap matching the chosen visual to the screen
280     GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid );
281     GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen );
282     if( pVis )
283     {
284         GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen );
285         GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol );
286         if( pDefVis != pVis )
287         {
288            pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() );
289            gdk_screen_set_default_colormap( pScreen, pDefCol );
290            #if OSL_DEBUG_LEVEL > 1
291            fprintf( stderr, "set new gdk color map for screen %d\n", nScreen );
292            #endif
293         }
294     }
295     #if OSL_DEBUG_LEVEL > 1
296     else
297         fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid );
298     #endif
299 }
300 
Dispatch(XEvent * pEvent)301 long GtkSalDisplay::Dispatch( XEvent* pEvent )
302 {
303     if( GetDisplay() == pEvent->xany.display )
304     {
305         GtkSalFrame* pFrame = findFrameByXWindow( pEvent->xany.window );
306         if( pFrame )
307         {
308             /*
309              * dispatchXEvent() returns true when the frame handled the event.
310              * This method returns a GdkFilterReturn, not the legacy Dispatch()
311              * continuation boolean.
312              */
313             return pFrame->dispatchXEvent( pEvent ) ? GDK_FILTER_REMOVE : GDK_FILTER_CONTINUE;
314         }
315     }
316 
317     return GDK_FILTER_CONTINUE;
318 }
319 
getFromXPM(const char * pBitmap,const char * pMask,int nWidth,int nHeight,int nXHot,int nYHot)320 GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap,
321                                       const char *pMask,
322                                       int nWidth, int nHeight,
323                                       int nXHot, int nYHot )
324 {
325     GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay );
326     GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) );
327     GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data
328             ( pDrawable, pBitmap, nWidth, nHeight );
329     GdkBitmap *pMaskPix = gdk_bitmap_create_from_data
330             ( pDrawable, pMask, nWidth, nHeight );
331     GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable );
332 
333     GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff };
334     GdkColor aBlack = { 0, 0, 0, 0 };
335 
336     gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE);
337     gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE);
338 
339     return gdk_cursor_new_from_pixmap
340             ( pBitmapPix, pMaskPix,
341               &aBlack, &aWhite, nXHot, nYHot);
342 }
343 
344 #define MAKE_CURSOR( vcl_name, name ) \
345     case vcl_name: \
346         pCursor = getFromXPM( (const char*)name##curs##_bits, (const char*)name##mask##_bits, \
347                               name##curs_width, name##curs_height, \
348                               name##curs_x_hot, name##curs_y_hot ); \
349         break
350 #define MAP_BUILTIN( vcl_name, gdk_name ) \
351         case vcl_name: \
352             pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
353             break
354 
getCursor(PointerStyle ePointerStyle)355 GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
356 {
357     if (ePointerStyle >= POINTER_COUNT)
358         return NULL;
359 
360     if ( !m_aCursors[ ePointerStyle ] )
361     {
362         GdkCursor *pCursor = NULL;
363 
364         switch( ePointerStyle )
365         {
366             MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR );
367             MAP_BUILTIN( POINTER_TEXT, GDK_XTERM );
368             MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW );
369             MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR );
370             MAP_BUILTIN( POINTER_WAIT, GDK_WATCH );
371 
372             MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW );
373             MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW );
374             MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW );
375             MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW );
376 
377             MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER );
378             MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER );
379             MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
380             MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
381 
382             MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE );
383             MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE );
384             MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE );
385             MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE );
386 
387             MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER );
388             MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER );
389             MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
390             MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
391 
392             MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW );
393             MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW );
394 
395             MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 );
396             MAP_BUILTIN( POINTER_HAND, GDK_HAND2 );
397             MAP_BUILTIN( POINTER_PEN, GDK_PENCIL );
398 
399             MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW );
400             MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW );
401 
402             MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR );
403 
404             MAKE_CURSOR( POINTER_NULL, null );
405             MAKE_CURSOR( POINTER_MAGNIFY, magnify_ );
406             MAKE_CURSOR( POINTER_FILL, fill_ );
407             MAKE_CURSOR( POINTER_MOVEDATA, movedata_ );
408             MAKE_CURSOR( POINTER_COPYDATA, copydata_ );
409             MAKE_CURSOR( POINTER_MOVEFILE, movefile_ );
410             MAKE_CURSOR( POINTER_COPYFILE, copyfile_ );
411             MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ );
412             MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ );
413             MAKE_CURSOR( POINTER_NOTALLOWED, notallow_ );
414             MAKE_CURSOR( POINTER_ROTATE, rotate_ );
415             MAKE_CURSOR( POINTER_HSHEAR, hshear_ );
416             MAKE_CURSOR( POINTER_VSHEAR, vshear_ );
417             MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ );
418             MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ );
419             MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ );
420             MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ );
421             MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ );
422             MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ );
423             MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ );
424             MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ );
425             MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ );
426             MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ );
427             MAKE_CURSOR( POINTER_MIRROR, mirror_ );
428             MAKE_CURSOR( POINTER_CROOK, crook_ );
429             MAKE_CURSOR( POINTER_CROP, crop_ );
430             MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ );
431             MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ );
432             MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ );
433             MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ );
434             MAKE_CURSOR( POINTER_LINKDATA, linkdata_ );
435             MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ );
436             MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ );
437             MAKE_CURSOR( POINTER_LINKFILE, linkfile_ );
438             MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ );
439             MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ );
440             MAKE_CURSOR( POINTER_CHART, chart_ );
441             MAKE_CURSOR( POINTER_DETECTIVE, detective_ );
442             MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ );
443             MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ );
444             MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ );
445             MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ );
446             MAKE_CURSOR( POINTER_CHAIN, chain_ );
447             MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ );
448             MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ );
449             MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ );
450             MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ );
451             MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ );
452             MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ );
453             MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ );
454             MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ );
455             MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ );
456             MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ );
457             MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ );
458             MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ );
459             MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ );
460             MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ );
461 
462             // --> FME 2004-07-30 #i32329# Enhanced table selection
463             MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ );
464             MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ );
465             MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ );
466             MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ );
467             MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ );
468             // <--
469 
470             // --> FME 2004-08-16 #i20119# Paintbrush tool
471             MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ );
472             // <--
473 
474         default:
475             fprintf( stderr, "pointer %d not implemented", ePointerStyle );
476             break;
477         }
478         if( !pCursor )
479             pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
480 
481         m_aCursors[ ePointerStyle ] = pCursor;
482     }
483 
484     return m_aCursors[ ePointerStyle ];
485 }
486 
CaptureMouse(SalFrame * pSFrame)487 int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame )
488 {
489     GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame);
490 
491     if( !pFrame )
492     {
493         if( m_pCapture )
494             static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
495         m_pCapture = NULL;
496         return 0;
497     }
498 
499     if( m_pCapture )
500     {
501         if( pFrame == m_pCapture )
502             return 1;
503         static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
504     }
505 
506     m_pCapture = pFrame;
507     static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE );
508     return 1;
509 }
510 
511 /***************************************************************************
512  * class GtkXLib
513  ***************************************************************************/
514 
515 class GtkXLib : public SalXLib
516 {
517     GtkSalDisplay       *m_pGtkSalDisplay;
518     std::list<GSource *> m_aSources;
519     GSource             *m_pTimeout;
520     GSource             *m_pUserEvent;
521     oslMutex             m_aDispatchMutex;
522     oslCondition         m_aDispatchCondition;
523     XIOErrorHandler      m_aOrigGTKXIOErrorHandler;
524 
525 public:
526     static gboolean      timeoutFn(gpointer data);
527     static gboolean      userEventFn(gpointer data);
528 
529     GtkXLib();
530     virtual ~GtkXLib();
531 
532     virtual void    Init();
533     virtual void    Yield( bool bWait, bool bHandleAllCurrentEvents );
534     virtual void    Insert( int fd, void* data,
535                             YieldFunc   pending,
536                             YieldFunc   queued,
537                             YieldFunc   handle );
538     virtual void    Remove( int fd );
539 
540     virtual void    StartTimer( sal_uLong nMS );
541     virtual void    StopTimer();
542     virtual void    Wakeup();
543     virtual void    PostUserEvent();
544 };
545 
GtkXLib()546 GtkXLib::GtkXLib()
547 {
548 #if OSL_DEBUG_LEVEL > 1
549     fprintf( stderr, "GtkXLib::GtkXLib()\n" );
550 #endif
551     m_pGtkSalDisplay = NULL;
552     m_pTimeout = NULL;
553     m_nTimeoutMS = 0;
554     m_pUserEvent = NULL;
555     m_aDispatchCondition = osl_createCondition();
556     m_aDispatchMutex = osl_createMutex();
557     m_aOrigGTKXIOErrorHandler = NULL;
558 }
559 
~GtkXLib()560 GtkXLib::~GtkXLib()
561 {
562 #if OSL_DEBUG_LEVEL > 1
563     fprintf( stderr, "GtkXLib::~GtkXLib()\n" );
564 #endif
565     StopTimer();
566      // sanity check: at this point nobody should be yielding, but wake them
567      // up anyway before the condition they're waiting on gets destroyed.
568     osl_setCondition( m_aDispatchCondition );
569     osl_destroyCondition( m_aDispatchCondition );
570     osl_destroyMutex( m_aDispatchMutex );
571 
572     PopXErrorLevel();
573     XSetIOErrorHandler (m_aOrigGTKXIOErrorHandler);
574 }
575 
Init()576 void GtkXLib::Init()
577 {
578     int i;
579 #if OSL_DEBUG_LEVEL > 1
580     fprintf( stderr, "GtkXLib::Init()\n" );
581 #endif
582     XrmInitialize();
583 
584     gtk_set_locale();
585 
586     /*
587      * open connection to X11 Display
588      * try in this order:
589      *  o  -display command line parameter,
590      *  o  $DISPLAY environment variable
591      *  o  default display
592      */
593 
594     GdkDisplay *pGdkDisp = NULL;
595 
596     // is there a -display command line parameter?
597     rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
598     int nParams = osl_getCommandArgCount();
599     rtl::OString aDisplay;
600     rtl::OUString aParam, aBin;
601     char** pCmdLineAry = new char*[ nParams+1 ];
602     osl_getExecutableFile( &aParam.pData );
603     osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
604     pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() );
605     for (i=0; i<nParams; i++)
606     {
607         osl_getCommandArg(i, &aParam.pData );
608         OString aBParam( OUStringToOString( aParam, aEnc ) );
609 
610         if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) )
611         {
612             pCmdLineAry[i+1] = g_strdup( "--display" );
613             osl_getCommandArg(i+1, &aParam.pData );
614             aDisplay = rtl::OUStringToOString( aParam, aEnc );
615         }
616         else
617             pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
618     }
619     // add executable
620     nParams++;
621 
622     g_set_application_name(X11SalData::getFrameClassName());
623 
624     // Set consistent name of the root accessible
625     rtl::OUString aAppName = Application::GetAppName();
626     if( aAppName.getLength() > 0 )
627     {
628         rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc);
629         g_set_prgname( aPrgName.getStr());
630     }
631 
632     // init gtk/gdk
633     gtk_init_check( &nParams, &pCmdLineAry );
634 
635     // gtk_init_check sets XError/XIOError handlers, we want our own one
636     m_aOrigGTKXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl );
637     PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) );
638 
639     for (i = 0; i < nParams; i++ )
640         g_free( pCmdLineAry[i] );
641     delete [] pCmdLineAry;
642 
643 #if OSL_DEBUG_LEVEL > 1
644     if (g_getenv ("SAL_DEBUG_UPDATES"))
645         gdk_window_set_debug_updates (TRUE);
646 #endif
647 
648     pGdkDisp = gdk_display_get_default();
649     if ( !pGdkDisp )
650     {
651         rtl::OUString aProgramFileURL;
652         osl_getExecutableFile( &aProgramFileURL.pData );
653         rtl::OUString aProgramSystemPath;
654         osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
655         rtl::OString  aProgramName = rtl::OUStringToOString(
656                                             aProgramSystemPath,
657                                             osl_getThreadTextEncoding() );
658         fprintf( stderr, "%s X11 error: Can't open display: %s\n",
659                 aProgramName.getStr(), aDisplay.getStr());
660         fprintf( stderr, "   Set DISPLAY environment variable, use -display option\n");
661         fprintf( stderr, "   or check permissions of your X-Server\n");
662         fprintf( stderr, "   (See \"man X\" resp. \"man xhost\" for details)\n");
663         fflush( stderr );
664         exit(0);
665     }
666 
667     /*
668      * if a -display switch was used, we need
669      * to set the environment accordingly since
670      * the clipboard build another connection
671      * to the xserver using $DISPLAY
672      */
673     rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY"));
674     const gchar *name = gdk_display_get_name( pGdkDisp );
675     rtl::OUString envValue(name, strlen(name), aEnc);
676     osl_setEnvironment(envVar.pData, envValue.pData);
677 
678     Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp );
679 
680     m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp );
681 
682     gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay );
683 
684     PushXErrorLevel( true );
685     SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
686     XSync( pDisp, False );
687 
688     pKbdExtension->UseExtension( ! HasXErrorOccured() );
689     PopXErrorLevel();
690 
691     m_pGtkSalDisplay->SetKbdExtension( pKbdExtension );
692 
693     g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay );
694 
695     // add signal handler to notify screen size changes
696     int nScreens = gdk_display_get_n_screens( pGdkDisp );
697     for( int n = 0; n < nScreens; n++ )
698     {
699         GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n );
700         if( pScreen )
701         {
702             g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay );
703             if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion
704                 g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay );
705         }
706     }
707 }
708 
709 extern "C"
710 {
call_timeoutFn(gpointer data)711     gboolean call_timeoutFn(gpointer data)
712     {
713         return GtkXLib::timeoutFn(data);
714     }
715 }
716 
timeoutFn(gpointer data)717 gboolean GtkXLib::timeoutFn(gpointer data)
718 {
719     SalData *pSalData = GetSalData();
720     GtkXLib *pThis = (GtkXLib *) data;
721 
722     pSalData->m_pInstance->GetYieldMutex()->acquire();
723 
724     if( pThis->m_pTimeout )
725     {
726         g_source_unref (pThis->m_pTimeout);
727         pThis->m_pTimeout = NULL;
728     }
729 
730     // Auto-restart immediately
731     pThis->StartTimer( pThis->m_nTimeoutMS );
732 
733     GetX11SalData()->Timeout();
734 
735     pSalData->m_pInstance->GetYieldMutex()->release();
736 
737     return FALSE;
738 }
739 
StartTimer(sal_uLong nMS)740 void GtkXLib::StartTimer( sal_uLong nMS )
741 {
742     m_nTimeoutMS = nMS; // for restarting
743 
744     if (m_pTimeout)
745     {
746         g_source_destroy (m_pTimeout);
747         g_source_unref (m_pTimeout);
748     }
749 
750     m_pTimeout = g_timeout_source_new (m_nTimeoutMS);
751     // #i36226# timers should be executed with lower priority
752     // than XEvents like in generic plugin
753     g_source_set_priority( m_pTimeout, G_PRIORITY_LOW );
754     g_source_set_can_recurse (m_pTimeout, TRUE);
755     g_source_set_callback (m_pTimeout, call_timeoutFn,
756                            (gpointer) this, NULL);
757     g_source_attach (m_pTimeout, g_main_context_default ());
758 
759     SalXLib::StartTimer( nMS );
760 }
761 
StopTimer()762 void GtkXLib::StopTimer()
763 {
764     SalXLib::StopTimer();
765 
766     if (m_pTimeout)
767     {
768         g_source_destroy (m_pTimeout);
769         g_source_unref (m_pTimeout);
770         m_pTimeout = NULL;
771     }
772 }
773 
774 extern "C"
775 {
call_userEventFn(gpointer data)776     gboolean call_userEventFn( gpointer data )
777     {
778         return GtkXLib::userEventFn( data );
779     }
780 }
781 
userEventFn(gpointer data)782 gboolean GtkXLib::userEventFn(gpointer data)
783 {
784     gboolean bContinue;
785     GtkXLib *pThis = (GtkXLib *) data;
786     SalData *pSalData = GetSalData();
787 
788     pSalData->m_pInstance->GetYieldMutex()->acquire();
789     pThis->m_pGtkSalDisplay->EventGuardAcquire();
790 
791     if( !pThis->m_pGtkSalDisplay->HasMoreEvents() )
792     {
793         if( pThis->m_pUserEvent )
794         {
795             g_source_unref (pThis->m_pUserEvent);
796             pThis->m_pUserEvent = NULL;
797         }
798         bContinue = FALSE;
799     }
800     else
801         bContinue = TRUE;
802 
803     pThis->m_pGtkSalDisplay->EventGuardRelease();
804 
805     pThis->m_pGtkSalDisplay->DispatchInternalEvent();
806 
807     pSalData->m_pInstance->GetYieldMutex()->release();
808 
809     return bContinue;
810 }
811 
812 // hEventGuard_ held during this invocation
PostUserEvent()813 void GtkXLib::PostUserEvent()
814 {
815     if( !m_pUserEvent ) // not pending anyway
816     {
817         m_pUserEvent = g_idle_source_new();
818         g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH );
819         g_source_set_can_recurse (m_pUserEvent, TRUE);
820         g_source_set_callback (m_pUserEvent, call_userEventFn,
821                                (gpointer) this, NULL);
822         g_source_attach (m_pUserEvent, g_main_context_default ());
823     }
824     Wakeup();
825 }
826 
Wakeup()827 void GtkXLib::Wakeup()
828 {
829     g_main_context_wakeup( g_main_context_default () );
830 }
831 
Yield(bool bWait,bool bHandleAllCurrentEvents)832 void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
833 {
834     /* #i33212# only enter g_main_context_iteration in one thread at any one
835      * time, else one of them potentially will never end as long as there is
836      * another thread in in there. Having only one yielding thread actually dispatch
837      * fits the vcl event model (see e.g. the generic plugin).
838      */
839 
840     bool bDispatchThread = false;
841     gboolean wasEvent = FALSE;
842     {
843         // release YieldMutex (and re-acquire at block end)
844         YieldMutexReleaser aReleaser;
845         if( osl_tryToAcquireMutex( m_aDispatchMutex ) )
846             bDispatchThread = true;
847         else if( ! bWait )
848             return; // someone else is waiting already, return
849 
850 
851         if( bDispatchThread )
852         {
853             int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
854             gboolean wasOneEvent = TRUE;
855             while( nMaxEvents-- && wasOneEvent )
856             {
857                 wasOneEvent = g_main_context_iteration( NULL, FALSE );
858                 if( wasOneEvent )
859                     wasEvent = TRUE;
860             }
861             if( bWait && ! wasEvent )
862                 wasEvent = g_main_context_iteration( NULL, TRUE );
863         }
864         else if( bWait )
865         {
866             /* #i41693# in case the dispatch thread hangs in join
867              * for this thread the condition will never be set
868              * workaround: timeout of 1 second a emergency exit
869              */
870             // we are the dispatch thread
871             osl_resetCondition( m_aDispatchCondition );
872             TimeValue aValue = { 1, 0 };
873             osl_waitCondition( m_aDispatchCondition, &aValue );
874         }
875     }
876 
877     if( bDispatchThread )
878     {
879         osl_releaseMutex( m_aDispatchMutex );
880         if( wasEvent )
881             osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
882     }
883 }
884 
885 extern "C" {
886 
887 typedef struct {
888     GSource       source;
889 
890     GPollFD       pollfd;
891     GIOCondition  condition;
892 
893     YieldFunc     pending;
894     YieldFunc     handle;
895     gpointer      user_data;
896 } SalWatch;
897 
898 static gboolean
sal_source_prepare(GSource * source,gint * timeout)899 sal_source_prepare (GSource *source,
900                     gint    *timeout)
901 {
902     SalWatch *watch = (SalWatch *)source;
903 
904     *timeout = -1;
905 
906     if (watch->pending &&
907         watch->pending (watch->pollfd.fd, watch->user_data)) {
908         watch->pollfd.revents |= watch->condition;
909         return TRUE;
910     }
911 
912     return FALSE;
913 }
914 
915 static gboolean
sal_source_check(GSource * source)916 sal_source_check (GSource *source)
917 {
918     SalWatch *watch = (SalWatch *)source;
919 
920     return watch->pollfd.revents & watch->condition;
921 }
922 
923 static gboolean
sal_source_dispatch(GSource * source,GSourceFunc,gpointer)924 sal_source_dispatch (GSource    *source,
925                      GSourceFunc,
926                      gpointer)
927 {
928     SalData *pSalData = GetSalData();
929     SalWatch *watch = (SalWatch *) source;
930 
931     pSalData->m_pInstance->GetYieldMutex()->acquire();
932 
933     watch->handle (watch->pollfd.fd, watch->user_data);
934 
935     pSalData->m_pInstance->GetYieldMutex()->release();
936 
937     return TRUE;
938 }
939 
940 static void
sal_source_finalize(GSource *)941 sal_source_finalize (GSource*)
942 {
943 }
944 
945 static GSourceFuncs sal_source_watch_funcs = {
946     sal_source_prepare,
947     sal_source_check,
948     sal_source_dispatch,
949     sal_source_finalize,
950     NULL,
951     NULL
952 };
953 
954 static GSource *
sal_source_create_watch(int fd,GIOCondition condition,YieldFunc pending,YieldFunc handle,gpointer user_data)955 sal_source_create_watch (int           fd,
956                          GIOCondition  condition,
957                          YieldFunc     pending,
958                          YieldFunc     handle,
959                          gpointer      user_data)
960 {
961     GSource      *source;
962     SalWatch     *watch;
963     GMainContext *context = g_main_context_default ();
964 
965     source = g_source_new (&sal_source_watch_funcs,
966                    sizeof (SalWatch));
967     watch = (SalWatch *) source;
968 
969     watch->pollfd.fd     = fd;
970     watch->pollfd.events = condition;
971     watch->condition = condition;
972     watch->pending   = pending;
973     watch->handle    = handle;
974     watch->user_data = user_data;
975 
976     g_source_set_can_recurse (source, TRUE);
977     g_source_add_poll (source, &watch->pollfd);
978     g_source_attach (source, context);
979 
980     return source;
981 }
982 
983 } // extern "C"
984 
Insert(int nFD,void * data,YieldFunc pending,YieldFunc,YieldFunc handle)985 void GtkXLib::Insert( int       nFD,
986               void     *data,
987               YieldFunc pending,
988               YieldFunc,
989               YieldFunc handle )
990 {
991     GSource *source = sal_source_create_watch
992         ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) |
993                        (G_IO_ERR|G_IO_HUP|G_IO_NVAL)),
994           pending, handle, data );
995     m_aSources.push_back( source );
996 }
997 
Remove(int nFD)998 void GtkXLib::Remove( int nFD )
999 {
1000     ::std::list< GSource * >::iterator it;
1001 
1002     for (it = m_aSources.begin(); it != m_aSources.end(); ++it)
1003     {
1004         SalWatch *watch = (SalWatch *) *it;
1005 
1006         if (watch->pollfd.fd == nFD)
1007         {
1008             m_aSources.erase( it );
1009 
1010             g_source_destroy ((GSource *)watch);
1011             g_source_unref   ((GSource *)watch);
1012             return;
1013         }
1014     }
1015 }
1016 
1017 /**********************************************************************
1018  * class GtkData
1019  **********************************************************************/
1020 
~GtkData()1021 GtkData::~GtkData()
1022 {
1023 }
1024 
Init()1025 void GtkData::Init()
1026 {
1027     pXLib_ = new GtkXLib();
1028     pXLib_->Init();
1029 }
1030 
1031 /* vim: set noet sw=4 ts=4: */
1032