merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / gtk / app / gtkdata.cxx
blob047938adc0db6974f18ed5c553bfdb513623f59a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gtkdata.cxx,v $
10 * $Revision: 1.42 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #define _SV_SALDATA_CXX
36 // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
38 #include <unistd.h>
39 #include <fcntl.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <limits.h>
45 #include <errno.h>
46 #include <poll.h>
47 #ifdef FREEBSD
48 #include <sys/types.h>
49 #include <sys/time.h>
50 #include <unistd.h>
51 #endif
52 #include <plugins/gtk/gtkdata.hxx>
53 #include <plugins/gtk/gtkinst.hxx>
54 #include <plugins/gtk/gtkframe.hxx>
55 #include <salobj.h>
56 #include <osl/thread.h>
57 #include <osl/process.h>
59 #include <tools/debug.hxx>
60 #include "i18n_im.hxx"
61 #include "i18n_xkb.hxx"
62 #include <wmadaptor.hxx>
64 #include "../../unx/source/inc/salcursors.h"
66 #include <vcl/svapp.hxx>
68 using namespace rtl;
69 using namespace vcl_sal;
71 /***************************************************************************
72 * class GtkDisplay *
73 ***************************************************************************/
75 GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay )
76 : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ),
77 m_pGdkDisplay( pDisplay ),
78 m_bStartupCompleted( false )
80 m_bUseRandRWrapper = false; // use gdk signal instead
81 for(int i = 0; i < POINTER_COUNT; i++)
82 m_aCursors[ i ] = NULL;
83 Init ();
86 GtkSalDisplay::~GtkSalDisplay()
88 if( !m_bStartupCompleted )
89 gdk_notify_startup_complete();
90 doDestruct();
92 for(int i = 0; i < POINTER_COUNT; i++)
93 if( m_aCursors[ i ] )
94 gdk_cursor_unref( m_aCursors[ i ] );
96 pDisp_ = NULL;
99 void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
101 if( m_pCapture == pFrame )
103 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
104 m_pCapture = NULL;
106 SalDisplay::deregisterFrame( pFrame );
109 extern "C" {
110 GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
111 GdkEvent* event,
112 gpointer data )
114 return GtkSalDisplay::filterGdkEvent( sys_event, event, data );
117 void signalKeysChanged( GdkKeymap*, gpointer data )
119 GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
120 pDisp->GetKeyboardName(TRUE);
123 void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data )
125 GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
126 pDisp->screenSizeChanged( pScreen );
129 void signalMonitorsChanged( GdkScreen* pScreen, gpointer data )
131 GtkSalDisplay* pDisp = (GtkSalDisplay*)data;
132 pDisp->monitorsChanged( pScreen );
137 GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event,
138 GdkEvent*,
139 gpointer data )
141 GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE;
143 XEvent *pEvent = (XEvent *)sys_event;
144 GtkSalDisplay *pDisplay = (GtkSalDisplay *)data;
146 // dispatch all XEvents to event callback
147 if( GetSalData()->m_pInstance->
148 CallEventCallback( pEvent, sizeof( XEvent ) ) )
149 aFilterReturn = GDK_FILTER_REMOVE;
151 GTK_YIELD_GRAB();
153 if (pDisplay->GetDisplay() == pEvent->xany.display )
155 // #i53471# gtk has no callback mechanism that lets us be notified
156 // when settings (as in XSETTING and opposed to styles) are changed.
157 // so we need to listen for corresponding property notifications here
158 // these should be rare enough so that we can assume that the settings
159 // actually change when a corresponding PropertyNotify occurs
160 if( pEvent->type == PropertyNotify &&
161 pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) &&
162 ! pDisplay->m_aFrames.empty()
165 pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED );
167 // let's see if one of our frames wants to swallow these events
168 // get the frame
169 for( std::list< SalFrame* >::const_iterator it = pDisplay->m_aFrames.begin();
170 it != pDisplay->m_aFrames.end(); ++it )
172 GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(*it);
173 if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window ||
174 ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) ||
175 ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window )
178 if( ! pFrame->Dispatch( pEvent ) )
179 aFilterReturn = GDK_FILTER_REMOVE;
180 break;
183 X11SalObject::Dispatch( pEvent );
186 return aFilterReturn;
189 void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen )
191 if( pScreen )
193 int nScreen = gdk_screen_get_number( pScreen );
194 if( nScreen < static_cast<int>(m_aScreens.size()) )
196 ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
197 if( rSD.m_bInit )
199 rSD.m_aSize = Size( gdk_screen_get_width( pScreen ),
200 gdk_screen_get_height( pScreen ) );
201 if( ! m_aFrames.empty() )
202 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
205 else
207 DBG_ERROR( "unknown screen changed size" );
212 void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen )
214 if( pScreen )
216 if( gdk_display_get_n_screens(m_pGdkDisplay) == 1 )
218 int nScreen = gdk_screen_get_number( pScreen );
219 if( nScreen == m_nDefaultScreen ) //To-Do, make m_aXineramaScreens a per-screen thing ?
221 gint nMonitors = gdk_screen_get_n_monitors(pScreen);
222 m_aXineramaScreens = std::vector<Rectangle>();
223 for (gint i = 0; i < nMonitors; ++i)
225 GdkRectangle dest;
226 gdk_screen_get_monitor_geometry(pScreen, i, &dest);
227 m_aXineramaScreens.push_back( Rectangle( Point(dest.x,
228 dest.y ), Size( dest.width, dest.height ) ) );
230 m_bXinerama = m_aXineramaScreens.size() > 1;
231 if( ! m_aFrames.empty() )
232 m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 );
234 else
236 DBG_ERROR( "monitors for non-default screen changed, extend-me" );
242 void GtkSalDisplay::initScreen( int nScreen ) const
244 if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) )
245 nScreen = m_nDefaultScreen;
246 ScreenData& rSD = const_cast<ScreenData&>(m_aScreens[nScreen]);
247 if( rSD.m_bInit )
248 return;
250 // choose visual for screen
251 SalDisplay::initScreen( nScreen );
252 // now set a gdk default colormap matching the chosen visual to the screen
253 GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid );
254 GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen );
255 if( pVis )
257 GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen );
258 GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol );
259 if( pDefVis != pVis )
261 pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() );
262 gdk_screen_set_default_colormap( pScreen, pDefCol );
263 #if OSL_DEBUG_LEVEL > 1
264 fprintf( stderr, "set new gdk color map for screen %d\n", nScreen );
265 #endif
268 #if OSL_DEBUG_LEVEL > 1
269 else
270 fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid );
271 #endif
274 long GtkSalDisplay::Dispatch( XEvent* pEvent )
276 if( GetDisplay() == pEvent->xany.display )
278 // let's see if one of our frames wants to swallow these events
279 // get the child frame
280 for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin();
281 it != m_aFrames.end(); ++it )
283 if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window )
284 return static_cast<GtkSalFrame*>(*it)->Dispatch( pEvent );
288 return GDK_FILTER_CONTINUE;
291 GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap,
292 const char *pMask,
293 int nWidth, int nHeight,
294 int nXHot, int nYHot )
296 GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay );
297 GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) );
298 GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data
299 ( pDrawable, pBitmap, nWidth, nHeight );
300 GdkBitmap *pMaskPix = gdk_bitmap_create_from_data
301 ( pDrawable, pMask, nWidth, nHeight );
302 GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable );
304 GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff };
305 GdkColor aBlack = { 0, 0, 0, 0 };
307 gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE);
308 gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE);
310 return gdk_cursor_new_from_pixmap
311 ( pBitmapPix, pMaskPix,
312 &aBlack, &aWhite, nXHot, nYHot);
315 #define MAKE_CURSOR( vcl_name, name ) \
316 case vcl_name: \
317 pCursor = getFromXPM( name##curs##_bits, name##mask##_bits, \
318 name##curs_width, name##curs_height, \
319 name##curs_x_hot, name##curs_y_hot ); \
320 break
321 #define MAP_BUILTIN( vcl_name, gdk_name ) \
322 case vcl_name: \
323 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
324 break
326 GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle )
328 if( ePointerStyle > POINTER_COUNT )
329 return NULL;
331 if ( !m_aCursors[ ePointerStyle ] )
333 GdkCursor *pCursor = NULL;
335 switch( ePointerStyle )
337 MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR );
338 MAP_BUILTIN( POINTER_TEXT, GDK_XTERM );
339 MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW );
340 MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR );
341 MAP_BUILTIN( POINTER_WAIT, GDK_WATCH );
343 MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW );
344 MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW );
345 MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW );
346 MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW );
348 MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER );
349 MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER );
350 MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
351 MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
353 MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE );
354 MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE );
355 MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE );
356 MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE );
358 MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER );
359 MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER );
360 MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER );
361 MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER );
363 MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW );
364 MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW );
366 MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 );
367 MAP_BUILTIN( POINTER_HAND, GDK_HAND2 );
368 MAP_BUILTIN( POINTER_PEN, GDK_PENCIL );
370 MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW );
371 MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW );
373 MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR );
375 MAKE_CURSOR( POINTER_NULL, null );
376 MAKE_CURSOR( POINTER_MAGNIFY, magnify_ );
377 MAKE_CURSOR( POINTER_FILL, fill_ );
378 MAKE_CURSOR( POINTER_MOVEDATA, movedata_ );
379 MAKE_CURSOR( POINTER_COPYDATA, copydata_ );
380 MAKE_CURSOR( POINTER_MOVEFILE, movefile_ );
381 MAKE_CURSOR( POINTER_COPYFILE, copyfile_ );
382 MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ );
383 MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ );
384 MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ );
385 MAKE_CURSOR( POINTER_ROTATE, rotate_ );
386 MAKE_CURSOR( POINTER_HSHEAR, hshear_ );
387 MAKE_CURSOR( POINTER_VSHEAR, vshear_ );
388 MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ );
389 MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ );
390 MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ );
391 MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ );
392 MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ );
393 MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ );
394 MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ );
395 MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ );
396 MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ );
397 MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ );
398 MAKE_CURSOR( POINTER_MIRROR, mirror_ );
399 MAKE_CURSOR( POINTER_CROOK, crook_ );
400 MAKE_CURSOR( POINTER_CROP, crop_ );
401 MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ );
402 MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ );
403 MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ );
404 MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ );
405 MAKE_CURSOR( POINTER_LINKDATA, linkdata_ );
406 MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ );
407 MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ );
408 MAKE_CURSOR( POINTER_LINKFILE, linkfile_ );
409 MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ );
410 MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ );
411 MAKE_CURSOR( POINTER_CHART, chart_ );
412 MAKE_CURSOR( POINTER_DETECTIVE, detective_ );
413 MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ );
414 MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ );
415 MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ );
416 MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ );
417 MAKE_CURSOR( POINTER_CHAIN, chain_ );
418 MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ );
419 MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ );
420 MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ );
421 MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ );
422 MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ );
423 MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ );
424 MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ );
425 MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ );
426 MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ );
427 MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ );
428 MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ );
429 MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ );
430 MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ );
431 MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ );
432 MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ );
433 MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ );
435 // --> FME 2004-07-30 #i32329# Enhanced table selection
436 MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ );
437 MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ );
438 MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ );
439 MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ );
440 MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ );
441 // <--
443 // --> FME 2004-08-16 #i20119# Paintbrush tool
444 MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ );
445 // <--
447 default:
448 fprintf( stderr, "pointer %d not implemented", ePointerStyle );
449 break;
451 if( !pCursor )
452 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR );
454 m_aCursors[ ePointerStyle ] = pCursor;
457 return m_aCursors[ ePointerStyle ];
460 int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame )
462 GtkSalFrame* pFrame = static_cast<GtkSalFrame*>(pSFrame);
464 if( !pFrame )
466 if( m_pCapture )
467 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
468 m_pCapture = NULL;
469 return 0;
472 if( m_pCapture )
474 if( pFrame == m_pCapture )
475 return 1;
476 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE );
479 m_pCapture = pFrame;
480 static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE );
481 return 1;
484 /***************************************************************************
485 * class GtkXLib *
486 ***************************************************************************/
488 class GtkXLib : public SalXLib
490 GtkSalDisplay *m_pGtkSalDisplay;
491 std::list<GSource *> m_aSources;
492 GSource *m_pTimeout;
493 GSource *m_pUserEvent;
494 oslMutex m_aDispatchMutex;
495 oslCondition m_aDispatchCondition;
497 public:
498 static gboolean timeoutFn(gpointer data);
499 static gboolean userEventFn(gpointer data);
501 GtkXLib();
502 virtual ~GtkXLib();
504 virtual void Init();
505 virtual void Yield( bool bWait, bool bHandleAllCurrentEvents );
506 virtual void Insert( int fd, void* data,
507 YieldFunc pending,
508 YieldFunc queued,
509 YieldFunc handle );
510 virtual void Remove( int fd );
512 virtual void StartTimer( ULONG nMS );
513 virtual void StopTimer();
514 virtual void Wakeup();
515 virtual void PostUserEvent();
518 GtkXLib::GtkXLib()
520 #if OSL_DEBUG_LEVEL > 1
521 fprintf( stderr, "GtkXLib::GtkXLib()\n" );
522 #endif
523 m_pGtkSalDisplay = NULL;
524 m_pTimeout = NULL;
525 m_nTimeoutMS = 0;
526 m_pUserEvent = NULL;
527 m_aDispatchCondition = osl_createCondition();
528 m_aDispatchMutex = osl_createMutex();
531 GtkXLib::~GtkXLib()
533 #if OSL_DEBUG_LEVEL > 1
534 fprintf( stderr, "GtkXLib::~GtkXLib()\n" );
535 #endif
536 StopTimer();
537 // sanity check: at this point nobody should be yielding, but wake them
538 // up anyway before the condition they're waiting on gets destroyed.
539 osl_setCondition( m_aDispatchCondition );
540 osl_destroyCondition( m_aDispatchCondition );
541 osl_destroyMutex( m_aDispatchMutex );
544 void GtkXLib::Init()
546 int i;
547 #if OSL_DEBUG_LEVEL > 1
548 fprintf( stderr, "GtkXLib::Init()\n" );
549 #endif
550 XrmInitialize();
552 gtk_set_locale();
555 * open connection to X11 Display
556 * try in this order:
557 * o -display command line parameter,
558 * o $DISPLAY environment variable
559 * o default display
562 GdkDisplay *pGdkDisp = NULL;
564 // is there a -display command line parameter?
565 rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
566 int nParams = osl_getCommandArgCount();
567 rtl::OString aDisplay;
568 rtl::OUString aParam, aBin;
569 char** pCmdLineAry = new char*[ nParams+1 ];
570 osl_getExecutableFile( &aParam.pData );
571 osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData );
572 pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() );
573 for (i=0; i<nParams; i++)
575 osl_getCommandArg(i, &aParam.pData );
576 OString aBParam( OUStringToOString( aParam, aEnc ) );
578 if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) )
580 pCmdLineAry[i+1] = g_strdup( "--display" );
581 osl_getCommandArg(i+1, &aParam.pData );
582 aDisplay = rtl::OUStringToOString( aParam, aEnc );
584 else
585 pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
587 // add executable
588 nParams++;
590 g_set_application_name(X11SalData::getFrameClassName());
592 // Set consistant name of the root accessible
593 rtl::OUString aAppName = Application::GetAppName();
594 if( aAppName.getLength() > 0 )
596 rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc);
597 g_set_prgname(aPrgName);
600 // init gtk/gdk
601 gtk_init_check( &nParams, &pCmdLineAry );
603 for (i = 0; i < nParams; i++ )
604 g_free( pCmdLineAry[i] );
605 delete [] pCmdLineAry;
607 #if OSL_DEBUG_LEVEL > 1
608 if (g_getenv ("SAL_DEBUG_UPDATES"))
609 gdk_window_set_debug_updates (TRUE);
610 #endif
612 pGdkDisp = gdk_display_get_default();
613 if ( !pGdkDisp )
615 rtl::OUString aProgramFileURL;
616 osl_getExecutableFile( &aProgramFileURL.pData );
617 rtl::OUString aProgramSystemPath;
618 osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
619 rtl::OString aProgramName = rtl::OUStringToOString(
620 aProgramSystemPath,
621 osl_getThreadTextEncoding() );
622 fprintf( stderr, "%s X11 error: Can't open display: %s\n",
623 aProgramName.getStr(), aDisplay.getStr());
624 fprintf( stderr, " Set DISPLAY environment variable, use -display option\n");
625 fprintf( stderr, " or check permissions of your X-Server\n");
626 fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n");
627 fflush( stderr );
628 exit(0);
632 * if a -display switch was used, we need
633 * to set the environment accoringly since
634 * the clipboard build another connection
635 * to the xserver using $DISPLAY
637 char *pPutEnvIsBroken = g_strdup_printf( "DISPLAY=%s",
638 gdk_display_get_name( pGdkDisp ) );
639 putenv( pPutEnvIsBroken );
641 Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp );
643 XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl );
644 XSetErrorHandler ( (XErrorHandler)X11SalData::XErrorHdl );
646 m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp );
648 gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay );
650 PushXErrorLevel( true );
651 SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp );
652 XSync( pDisp, False );
654 pKbdExtension->UseExtension( ! HasXErrorOccured() );
655 PopXErrorLevel();
657 m_pGtkSalDisplay->SetKbdExtension( pKbdExtension );
659 g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay );
661 // add signal handler to notify screen size changes
662 int nScreens = gdk_display_get_n_screens( pGdkDisp );
663 for( int n = 0; n < nScreens; n++ )
665 GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n );
666 if( pScreen )
668 g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay );
669 g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay );
674 extern "C"
676 gboolean call_timeoutFn(gpointer data)
678 return GtkXLib::timeoutFn(data);
682 gboolean GtkXLib::timeoutFn(gpointer data)
684 SalData *pSalData = GetSalData();
685 GtkXLib *pThis = (GtkXLib *) data;
687 pSalData->m_pInstance->GetYieldMutex()->acquire();
689 if( pThis->m_pTimeout )
691 g_source_unref (pThis->m_pTimeout);
692 pThis->m_pTimeout = NULL;
695 // Auto-restart immediately
696 pThis->StartTimer( pThis->m_nTimeoutMS );
698 GetX11SalData()->Timeout();
700 pSalData->m_pInstance->GetYieldMutex()->release();
702 return FALSE;
705 void GtkXLib::StartTimer( ULONG nMS )
707 m_nTimeoutMS = nMS; // for restarting
709 if (m_pTimeout)
711 g_source_destroy (m_pTimeout);
712 g_source_unref (m_pTimeout);
715 m_pTimeout = g_timeout_source_new (m_nTimeoutMS);
716 // #i36226# timers should be executed with lower priority
717 // than XEvents like in generic plugin
718 g_source_set_priority( m_pTimeout, G_PRIORITY_LOW );
719 g_source_set_can_recurse (m_pTimeout, TRUE);
720 g_source_set_callback (m_pTimeout, call_timeoutFn,
721 (gpointer) this, NULL);
722 g_source_attach (m_pTimeout, g_main_context_default ());
724 SalXLib::StartTimer( nMS );
727 void GtkXLib::StopTimer()
729 SalXLib::StopTimer();
731 if (m_pTimeout)
733 g_source_destroy (m_pTimeout);
734 g_source_unref (m_pTimeout);
735 m_pTimeout = NULL;
739 extern "C"
741 gboolean call_userEventFn( gpointer data )
743 return GtkXLib::userEventFn( data );
747 gboolean GtkXLib::userEventFn(gpointer data)
749 gboolean bContinue;
750 GtkXLib *pThis = (GtkXLib *) data;
751 SalData *pSalData = GetSalData();
753 pSalData->m_pInstance->GetYieldMutex()->acquire();
754 pThis->m_pGtkSalDisplay->EventGuardAcquire();
756 if( !pThis->m_pGtkSalDisplay->HasMoreEvents() )
758 if( pThis->m_pUserEvent )
760 g_source_unref (pThis->m_pUserEvent);
761 pThis->m_pUserEvent = NULL;
763 bContinue = FALSE;
765 else
766 bContinue = TRUE;
768 pThis->m_pGtkSalDisplay->EventGuardRelease();
770 pThis->m_pGtkSalDisplay->DispatchInternalEvent();
772 pSalData->m_pInstance->GetYieldMutex()->release();
774 return bContinue;
777 // hEventGuard_ held during this invocation
778 void GtkXLib::PostUserEvent()
780 if( !m_pUserEvent ) // not pending anyway
782 m_pUserEvent = g_idle_source_new();
783 g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH );
784 g_source_set_can_recurse (m_pUserEvent, TRUE);
785 g_source_set_callback (m_pUserEvent, call_userEventFn,
786 (gpointer) this, NULL);
787 g_source_attach (m_pUserEvent, g_main_context_default ());
789 Wakeup();
792 void GtkXLib::Wakeup()
794 g_main_context_wakeup( g_main_context_default () );
797 void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents )
799 /* #i33212# only enter g_main_context_iteration in one thread at any one
800 * time, else one of them potentially will never end as long as there is
801 * another thread in in there. Having only one yieldin thread actually dispatch
802 * fits the vcl event model (see e.g. the generic plugin).
805 bool bDispatchThread = false;
807 // release YieldMutex (and re-acquire at block end)
808 YieldMutexReleaser aReleaser;
809 if( osl_tryToAcquireMutex( m_aDispatchMutex ) )
811 // we are the dispatch thread
812 osl_resetCondition( m_aDispatchCondition );
813 bDispatchThread = true;
815 else if( ! bWait )
816 return; // someone else is waiting already, return
819 if( bDispatchThread )
821 int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
822 gboolean wasEvent = FALSE, wasOneEvent = TRUE;
823 while( nMaxEvents-- && wasOneEvent )
825 wasOneEvent = g_main_context_iteration( NULL, FALSE );
826 if( wasOneEvent )
827 wasEvent = TRUE;
829 if( bWait && ! wasEvent )
830 g_main_context_iteration( NULL, TRUE );
832 else if( userEventFn( this ) )
834 /* #i41693# in case the dispatch thread hangs in join
835 * for this thread the condition will never be set
836 * workaround: timeout of 1 second a emergency exit
838 TimeValue aValue;
839 aValue.Seconds = 1;
840 aValue.Nanosec = 0;
841 osl_waitCondition( m_aDispatchCondition, &aValue );
845 if( bDispatchThread )
847 osl_releaseMutex( m_aDispatchMutex );
848 osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields
849 osl_resetCondition( m_aDispatchCondition );
853 extern "C" {
855 typedef struct {
856 GSource source;
858 GPollFD pollfd;
859 GIOCondition condition;
861 YieldFunc pending;
862 YieldFunc handle;
863 gpointer user_data;
864 } SalWatch;
866 static gboolean
867 sal_source_prepare (GSource *source,
868 gint *timeout)
870 SalWatch *watch = (SalWatch *)source;
872 *timeout = -1;
874 if (watch->pending &&
875 watch->pending (watch->pollfd.fd, watch->user_data)) {
876 watch->pollfd.revents |= watch->condition;
877 return TRUE;
880 return FALSE;
883 static gboolean
884 sal_source_check (GSource *source)
886 SalWatch *watch = (SalWatch *)source;
888 return watch->pollfd.revents & watch->condition;
891 static gboolean
892 sal_source_dispatch (GSource *source,
893 GSourceFunc,
894 gpointer)
896 SalData *pSalData = GetSalData();
897 SalWatch *watch = (SalWatch *) source;
899 pSalData->m_pInstance->GetYieldMutex()->acquire();
901 watch->handle (watch->pollfd.fd, watch->user_data);
903 pSalData->m_pInstance->GetYieldMutex()->release();
905 return TRUE;
908 static void
909 sal_source_finalize (GSource*)
913 static GSourceFuncs sal_source_watch_funcs = {
914 sal_source_prepare,
915 sal_source_check,
916 sal_source_dispatch,
917 sal_source_finalize,
918 NULL,
919 NULL
922 static GSource *
923 sal_source_create_watch (int fd,
924 GIOCondition condition,
925 YieldFunc pending,
926 YieldFunc handle,
927 gpointer user_data)
929 GSource *source;
930 SalWatch *watch;
931 GMainContext *context = g_main_context_default ();
933 source = g_source_new (&sal_source_watch_funcs,
934 sizeof (SalWatch));
935 watch = (SalWatch *) source;
937 watch->pollfd.fd = fd;
938 watch->pollfd.events = condition;
939 watch->condition = condition;
940 watch->pending = pending;
941 watch->handle = handle;
942 watch->user_data = user_data;
944 g_source_set_can_recurse (source, TRUE);
945 g_source_add_poll (source, &watch->pollfd);
946 g_source_attach (source, context);
948 return source;
951 } // extern "C"
953 void GtkXLib::Insert( int nFD,
954 void *data,
955 YieldFunc pending,
956 YieldFunc,
957 YieldFunc handle )
959 GSource *source = sal_source_create_watch
960 ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) |
961 (G_IO_ERR|G_IO_HUP|G_IO_NVAL)),
962 pending, handle, data );
963 m_aSources.push_back( source );
966 void GtkXLib::Remove( int nFD )
968 ::std::list< GSource * >::iterator it;
970 for (it = m_aSources.begin(); it != m_aSources.end(); ++it)
972 SalWatch *watch = (SalWatch *) *it;
974 if (watch->pollfd.fd == nFD)
976 m_aSources.erase( it );
978 g_source_destroy ((GSource *)watch);
979 g_source_unref ((GSource *)watch);
980 return;
985 /**********************************************************************
986 * class GtkData *
987 **********************************************************************/
989 GtkData::~GtkData()
993 void GtkData::Init()
995 pXLib_ = new GtkXLib();
996 pXLib_->Init();