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