xref: /trunk/main/vcl/unx/gtk/app/gtkdata.cxx (revision cdf0e10c)
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