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