xref: /AOO41X/main/vcl/unx/gtk/app/gtkdata.cxx (revision 24c56ab9f1bd1305754aa2f564704f38ff57627e)
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 consistant 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