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