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