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