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