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