/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #define _SV_SALDATA_CXX // -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #include #include #include #include #include #include #include #include #ifdef FREEBSD #include #include #include #endif #include #include #include #include #include #include #include #include "unx/i18n_im.hxx" #include "unx/i18n_xkb.hxx" #include #include "unx/x11_cursors/salcursors.h" #include using namespace rtl; using namespace vcl_sal; /*************************************************************************** * class GtkDisplay * ***************************************************************************/ GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) : SalDisplay( gdk_x11_display_get_xdisplay( pDisplay ) ), m_pGdkDisplay( pDisplay ), m_bStartupCompleted( false ) { m_bUseRandRWrapper = false; // use gdk signal instead for(int i = 0; i < POINTER_COUNT; i++) m_aCursors[ i ] = NULL; Init (); } GtkSalDisplay::~GtkSalDisplay() { if( !m_bStartupCompleted ) gdk_notify_startup_complete(); doDestruct(); for(int i = 0; i < POINTER_COUNT; i++) if( m_aCursors[ i ] ) gdk_cursor_unref( m_aCursors[ i ] ); pDisp_ = NULL; } void GtkSalDisplay::deregisterFrame( SalFrame* pFrame ) { if( m_pCapture == pFrame ) { static_cast(m_pCapture)->grabPointer( FALSE ); m_pCapture = NULL; } SalDisplay::deregisterFrame( pFrame ); } extern "C" { GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event, GdkEvent* event, gpointer data ) { return GtkSalDisplay::filterGdkEvent( sys_event, event, data ); } void signalKeysChanged( GdkKeymap*, gpointer data ) { GtkSalDisplay* pDisp = (GtkSalDisplay*)data; pDisp->GetKeyboardName(TRUE); } void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data ) { GtkSalDisplay* pDisp = (GtkSalDisplay*)data; pDisp->screenSizeChanged( pScreen ); } void signalMonitorsChanged( GdkScreen* pScreen, gpointer data ) { GtkSalDisplay* pDisp = (GtkSalDisplay*)data; pDisp->monitorsChanged( pScreen ); } } GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* sys_event, GdkEvent*, gpointer data ) { GdkFilterReturn aFilterReturn = GDK_FILTER_CONTINUE; XEvent *pEvent = (XEvent *)sys_event; GtkSalDisplay *pDisplay = (GtkSalDisplay *)data; // dispatch all XEvents to event callback if( GetSalData()->m_pInstance-> CallEventCallback( pEvent, sizeof( XEvent ) ) ) aFilterReturn = GDK_FILTER_REMOVE; GTK_YIELD_GRAB(); if (pDisplay->GetDisplay() == pEvent->xany.display ) { // #i53471# gtk has no callback mechanism that lets us be notified // when settings (as in XSETTING and opposed to styles) are changed. // so we need to listen for corresponding property notifications here // these should be rare enough so that we can assume that the settings // actually change when a corresponding PropertyNotify occurs if( pEvent->type == PropertyNotify && pEvent->xproperty.atom == pDisplay->getWMAdaptor()->getAtom( WMAdaptor::XSETTINGS ) && ! pDisplay->m_aFrames.empty() ) { pDisplay->SendInternalEvent( pDisplay->m_aFrames.front(), NULL, SALEVENT_SETTINGSCHANGED ); } // let's see if one of our frames wants to swallow these events // get the frame for( std::list< SalFrame* >::const_iterator it = pDisplay->m_aFrames.begin(); it != pDisplay->m_aFrames.end(); ++it ) { GtkSalFrame* pFrame = static_cast(*it); if( (GdkNativeWindow)pFrame->GetSystemData()->aWindow == pEvent->xany.window || ( pFrame->getForeignParent() && pFrame->getForeignParentWindow() == pEvent->xany.window ) || ( pFrame->getForeignTopLevel() && pFrame->getForeignTopLevelWindow() == pEvent->xany.window ) ) { if( ! pFrame->Dispatch( pEvent ) ) aFilterReturn = GDK_FILTER_REMOVE; break; } } X11SalObject::Dispatch( pEvent ); } return aFilterReturn; } void GtkSalDisplay::screenSizeChanged( GdkScreen* pScreen ) { if( pScreen ) { int nScreen = gdk_screen_get_number( pScreen ); if( nScreen < static_cast(m_aScreens.size()) ) { ScreenData& rSD = const_cast(m_aScreens[nScreen]); if( rSD.m_bInit ) { rSD.m_aSize = Size( gdk_screen_get_width( pScreen ), gdk_screen_get_height( pScreen ) ); if( ! m_aFrames.empty() ) m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); } } else { DBG_ERROR( "unknown screen changed size" ); } } } void GtkSalDisplay::monitorsChanged( GdkScreen* pScreen ) { /* Caution: since we support the _NET_WM_FULLSCREEN_MONITORS property now and the EWMH spec says, the index used for that needs to be that of the Xinerama extension, we need to ensure that the order of m_aXineramaScreens is actually intact. gdk_screen_get_monitor_geometry however has a different sort order that has a default monitor number Xinerama returns the default monitor as 0. That means if we fill in the multiple montors vector from gdk, we'll get the wrong order unless the default monitor is incidentally the same (number 0). Given that XRandR (which is what gdk_screen_get_monitor_geometry is based on) is supposed to replace Xinerama, this is bound to get a problem at some time again, unfortunately there does not currently seem to be a way to map the returns of xinerama to that of randr. Currently getting Xinerama values again works with updated values, given a new enough Xserver. */ InitXinerama(); (void)pScreen; #if 0 if( pScreen ) { if( gdk_display_get_n_screens(m_pGdkDisplay) == 1 ) { int nScreen = gdk_screen_get_number( pScreen ); if( nScreen == m_nDefaultScreen ) //To-Do, make m_aXineramaScreens a per-screen thing ? { gint nMonitors = gdk_screen_get_n_monitors(pScreen); m_aXineramaScreens = std::vector(); m_aXineramaScreenIndexMap = std::vector(nMonitors); for (gint i = 0; i < nMonitors; ++i) { GdkRectangle dest; gdk_screen_get_monitor_geometry(pScreen, i, &dest); m_aXineramaScreenIndexMap[i] = addXineramaScreenUnique( dest.x, dest.y, dest.width, dest.height ); } m_bXinerama = m_aXineramaScreens.size() > 1; if( ! m_aFrames.empty() ) m_aFrames.front()->CallCallback( SALEVENT_DISPLAYCHANGED, 0 ); } else { DBG_ERROR( "monitors for non-default screen changed, extend-me" ); } } } #endif } extern "C" { typedef gint(* screen_get_primary_monitor)(GdkScreen *screen); } int GtkSalDisplay::GetDefaultMonitorNumber() const { int n = 0; // currently disabled, see remarks in monitorsChanged #if 0 GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, m_nDefaultScreen ); #if GTK_CHECK_VERSION(2,20,0) n = gdk_screen_get_primary_monitor(pScreen); #else static screen_get_primary_monitor sym_gdk_screen_get_primary_monitor = (screen_get_primary_monitor)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_primary_monitor" ); if (sym_gdk_screen_get_primary_monitor) n = sym_gdk_screen_get_primary_monitor( pScreen ); #endif if( n >= 0 && size_t(n) < m_aXineramaScreenIndexMap.size() ) n = m_aXineramaScreenIndexMap[n]; #endif return n; } void GtkSalDisplay::initScreen( int nScreen ) const { if( nScreen < 0 || nScreen >= static_cast(m_aScreens.size()) ) nScreen = m_nDefaultScreen; ScreenData& rSD = const_cast(m_aScreens[nScreen]); if( rSD.m_bInit ) return; // choose visual for screen SalDisplay::initScreen( nScreen ); // now set a gdk default colormap matching the chosen visual to the screen GdkVisual* pVis = gdkx_visual_get( rSD.m_aVisual.visualid ); GdkScreen* pScreen = gdk_display_get_screen( m_pGdkDisplay, nScreen ); if( pVis ) { GdkColormap* pDefCol = gdk_screen_get_default_colormap( pScreen ); GdkVisual* pDefVis = gdk_colormap_get_visual( pDefCol ); if( pDefVis != pVis ) { pDefCol = gdk_x11_colormap_foreign_new( pVis, rSD.m_aColormap.GetXColormap() ); gdk_screen_set_default_colormap( pScreen, pDefCol ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "set new gdk color map for screen %d\n", nScreen ); #endif } } #if OSL_DEBUG_LEVEL > 1 else fprintf( stderr, "not GdkVisual for visual id %d\n", (int)rSD.m_aVisual.visualid ); #endif } long GtkSalDisplay::Dispatch( XEvent* pEvent ) { if( GetDisplay() == pEvent->xany.display ) { // let's see if one of our frames wants to swallow these events // get the child frame for( std::list< SalFrame* >::const_iterator it = m_aFrames.begin(); it != m_aFrames.end(); ++it ) { if( (GdkNativeWindow)(*it)->GetSystemData()->aWindow == pEvent->xany.window ) return static_cast(*it)->Dispatch( pEvent ); } } return GDK_FILTER_CONTINUE; } GdkCursor* GtkSalDisplay::getFromXPM( const char *pBitmap, const char *pMask, int nWidth, int nHeight, int nXHot, int nYHot ) { GdkScreen *pScreen = gdk_display_get_default_screen( m_pGdkDisplay ); GdkDrawable *pDrawable = GDK_DRAWABLE( gdk_screen_get_root_window (pScreen) ); GdkBitmap *pBitmapPix = gdk_bitmap_create_from_data ( pDrawable, pBitmap, nWidth, nHeight ); GdkBitmap *pMaskPix = gdk_bitmap_create_from_data ( pDrawable, pMask, nWidth, nHeight ); GdkColormap *pColormap = gdk_drawable_get_colormap( pDrawable ); GdkColor aWhite = { 0, 0xffff, 0xffff, 0xffff }; GdkColor aBlack = { 0, 0, 0, 0 }; gdk_colormap_alloc_color( pColormap, &aBlack, FALSE, TRUE); gdk_colormap_alloc_color( pColormap, &aWhite, FALSE, TRUE); return gdk_cursor_new_from_pixmap ( pBitmapPix, pMaskPix, &aBlack, &aWhite, nXHot, nYHot); } #define MAKE_CURSOR( vcl_name, name ) \ case vcl_name: \ pCursor = getFromXPM( (const char*)name##curs##_bits, (const char*)name##mask##_bits, \ name##curs_width, name##curs_height, \ name##curs_x_hot, name##curs_y_hot ); \ break #define MAP_BUILTIN( vcl_name, gdk_name ) \ case vcl_name: \ pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \ break GdkCursor *GtkSalDisplay::getCursor( PointerStyle ePointerStyle ) { if (ePointerStyle >= POINTER_COUNT) return NULL; if ( !m_aCursors[ ePointerStyle ] ) { GdkCursor *pCursor = NULL; switch( ePointerStyle ) { MAP_BUILTIN( POINTER_ARROW, GDK_LEFT_PTR ); MAP_BUILTIN( POINTER_TEXT, GDK_XTERM ); MAP_BUILTIN( POINTER_HELP, GDK_QUESTION_ARROW ); MAP_BUILTIN( POINTER_CROSS, GDK_CROSSHAIR ); MAP_BUILTIN( POINTER_WAIT, GDK_WATCH ); MAP_BUILTIN( POINTER_NSIZE, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_SSIZE, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_WSIZE, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_ESIZE, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_NWSIZE, GDK_TOP_LEFT_CORNER ); MAP_BUILTIN( POINTER_NESIZE, GDK_TOP_RIGHT_CORNER ); MAP_BUILTIN( POINTER_SWSIZE, GDK_BOTTOM_LEFT_CORNER ); MAP_BUILTIN( POINTER_SESIZE, GDK_BOTTOM_RIGHT_CORNER ); MAP_BUILTIN( POINTER_WINDOW_NSIZE, GDK_TOP_SIDE ); MAP_BUILTIN( POINTER_WINDOW_SSIZE, GDK_BOTTOM_SIDE ); MAP_BUILTIN( POINTER_WINDOW_WSIZE, GDK_LEFT_SIDE ); MAP_BUILTIN( POINTER_WINDOW_ESIZE, GDK_RIGHT_SIDE ); MAP_BUILTIN( POINTER_WINDOW_NWSIZE, GDK_TOP_LEFT_CORNER ); MAP_BUILTIN( POINTER_WINDOW_NESIZE, GDK_TOP_RIGHT_CORNER ); MAP_BUILTIN( POINTER_WINDOW_SWSIZE, GDK_BOTTOM_LEFT_CORNER ); MAP_BUILTIN( POINTER_WINDOW_SESIZE, GDK_BOTTOM_RIGHT_CORNER ); MAP_BUILTIN( POINTER_HSIZEBAR, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_VSIZEBAR, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_REFHAND, GDK_HAND1 ); MAP_BUILTIN( POINTER_HAND, GDK_HAND2 ); MAP_BUILTIN( POINTER_PEN, GDK_PENCIL ); MAP_BUILTIN( POINTER_HSPLIT, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_VSPLIT, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( POINTER_MOVE, GDK_FLEUR ); MAKE_CURSOR( POINTER_NULL, null ); MAKE_CURSOR( POINTER_MAGNIFY, magnify_ ); MAKE_CURSOR( POINTER_FILL, fill_ ); MAKE_CURSOR( POINTER_MOVEDATA, movedata_ ); MAKE_CURSOR( POINTER_COPYDATA, copydata_ ); MAKE_CURSOR( POINTER_MOVEFILE, movefile_ ); MAKE_CURSOR( POINTER_COPYFILE, copyfile_ ); MAKE_CURSOR( POINTER_MOVEFILES, movefiles_ ); MAKE_CURSOR( POINTER_COPYFILES, copyfiles_ ); MAKE_CURSOR( POINTER_NOTALLOWED, nodrop_ ); MAKE_CURSOR( POINTER_ROTATE, rotate_ ); MAKE_CURSOR( POINTER_HSHEAR, hshear_ ); MAKE_CURSOR( POINTER_VSHEAR, vshear_ ); MAKE_CURSOR( POINTER_DRAW_LINE, drawline_ ); MAKE_CURSOR( POINTER_DRAW_RECT, drawrect_ ); MAKE_CURSOR( POINTER_DRAW_POLYGON, drawpolygon_ ); MAKE_CURSOR( POINTER_DRAW_BEZIER, drawbezier_ ); MAKE_CURSOR( POINTER_DRAW_ARC, drawarc_ ); MAKE_CURSOR( POINTER_DRAW_PIE, drawpie_ ); MAKE_CURSOR( POINTER_DRAW_CIRCLECUT, drawcirclecut_ ); MAKE_CURSOR( POINTER_DRAW_ELLIPSE, drawellipse_ ); MAKE_CURSOR( POINTER_DRAW_CONNECT, drawconnect_ ); MAKE_CURSOR( POINTER_DRAW_TEXT, drawtext_ ); MAKE_CURSOR( POINTER_MIRROR, mirror_ ); MAKE_CURSOR( POINTER_CROOK, crook_ ); MAKE_CURSOR( POINTER_CROP, crop_ ); MAKE_CURSOR( POINTER_MOVEPOINT, movepoint_ ); MAKE_CURSOR( POINTER_MOVEBEZIERWEIGHT, movebezierweight_ ); MAKE_CURSOR( POINTER_DRAW_FREEHAND, drawfreehand_ ); MAKE_CURSOR( POINTER_DRAW_CAPTION, drawcaption_ ); MAKE_CURSOR( POINTER_LINKDATA, linkdata_ ); MAKE_CURSOR( POINTER_MOVEDATALINK, movedlnk_ ); MAKE_CURSOR( POINTER_COPYDATALINK, copydlnk_ ); MAKE_CURSOR( POINTER_LINKFILE, linkfile_ ); MAKE_CURSOR( POINTER_MOVEFILELINK, moveflnk_ ); MAKE_CURSOR( POINTER_COPYFILELINK, copyflnk_ ); MAKE_CURSOR( POINTER_CHART, chart_ ); MAKE_CURSOR( POINTER_DETECTIVE, detective_ ); MAKE_CURSOR( POINTER_PIVOT_COL, pivotcol_ ); MAKE_CURSOR( POINTER_PIVOT_ROW, pivotrow_ ); MAKE_CURSOR( POINTER_PIVOT_FIELD, pivotfld_ ); MAKE_CURSOR( POINTER_PIVOT_DELETE, pivotdel_ ); MAKE_CURSOR( POINTER_CHAIN, chain_ ); MAKE_CURSOR( POINTER_CHAIN_NOTALLOWED, chainnot_ ); MAKE_CURSOR( POINTER_TIMEEVENT_MOVE, timemove_ ); MAKE_CURSOR( POINTER_TIMEEVENT_SIZE, timesize_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_N, asn_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_S, ass_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_W, asw_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_E, ase_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_NW, asnw_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_NE, asne_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_SW, assw_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_SE, asse_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_NS, asns_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_WE, aswe_ ); MAKE_CURSOR( POINTER_AUTOSCROLL_NSWE, asnswe_ ); MAKE_CURSOR( POINTER_AIRBRUSH, airbrush_ ); MAKE_CURSOR( POINTER_TEXT_VERTICAL, vertcurs_ ); // --> FME 2004-07-30 #i32329# Enhanced table selection MAKE_CURSOR( POINTER_TAB_SELECT_S, tblsels_ ); MAKE_CURSOR( POINTER_TAB_SELECT_E, tblsele_ ); MAKE_CURSOR( POINTER_TAB_SELECT_SE, tblselse_ ); MAKE_CURSOR( POINTER_TAB_SELECT_W, tblselw_ ); MAKE_CURSOR( POINTER_TAB_SELECT_SW, tblselsw_ ); // <-- // --> FME 2004-08-16 #i20119# Paintbrush tool MAKE_CURSOR( POINTER_PAINTBRUSH, paintbrush_ ); // <-- default: fprintf( stderr, "pointer %d not implemented", ePointerStyle ); break; } if( !pCursor ) pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, GDK_LEFT_PTR ); m_aCursors[ ePointerStyle ] = pCursor; } return m_aCursors[ ePointerStyle ]; } int GtkSalDisplay::CaptureMouse( SalFrame* pSFrame ) { GtkSalFrame* pFrame = static_cast(pSFrame); if( !pFrame ) { if( m_pCapture ) static_cast(m_pCapture)->grabPointer( FALSE ); m_pCapture = NULL; return 0; } if( m_pCapture ) { if( pFrame == m_pCapture ) return 1; static_cast(m_pCapture)->grabPointer( FALSE ); } m_pCapture = pFrame; static_cast(pFrame)->grabPointer( TRUE ); return 1; } /*************************************************************************** * class GtkXLib * ***************************************************************************/ class GtkXLib : public SalXLib { GtkSalDisplay *m_pGtkSalDisplay; std::list m_aSources; GSource *m_pTimeout; GSource *m_pUserEvent; oslMutex m_aDispatchMutex; oslCondition m_aDispatchCondition; XIOErrorHandler m_aOrigGTKXIOErrorHandler; public: static gboolean timeoutFn(gpointer data); static gboolean userEventFn(gpointer data); GtkXLib(); virtual ~GtkXLib(); virtual void Init(); virtual void Yield( bool bWait, bool bHandleAllCurrentEvents ); virtual void Insert( int fd, void* data, YieldFunc pending, YieldFunc queued, YieldFunc handle ); virtual void Remove( int fd ); virtual void StartTimer( sal_uLong nMS ); virtual void StopTimer(); virtual void Wakeup(); virtual void PostUserEvent(); }; GtkXLib::GtkXLib() { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "GtkXLib::GtkXLib()\n" ); #endif m_pGtkSalDisplay = NULL; m_pTimeout = NULL; m_nTimeoutMS = 0; m_pUserEvent = NULL; m_aDispatchCondition = osl_createCondition(); m_aDispatchMutex = osl_createMutex(); m_aOrigGTKXIOErrorHandler = NULL; } GtkXLib::~GtkXLib() { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "GtkXLib::~GtkXLib()\n" ); #endif StopTimer(); // sanity check: at this point nobody should be yielding, but wake them // up anyway before the condition they're waiting on gets destroyed. osl_setCondition( m_aDispatchCondition ); osl_destroyCondition( m_aDispatchCondition ); osl_destroyMutex( m_aDispatchMutex ); PopXErrorLevel(); XSetIOErrorHandler (m_aOrigGTKXIOErrorHandler); } void GtkXLib::Init() { int i; #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "GtkXLib::Init()\n" ); #endif XrmInitialize(); gtk_set_locale(); /* * open connection to X11 Display * try in this order: * o -display command line parameter, * o $DISPLAY environment variable * o default display */ GdkDisplay *pGdkDisp = NULL; // is there a -display command line parameter? rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); int nParams = osl_getCommandArgCount(); rtl::OString aDisplay; rtl::OUString aParam, aBin; char** pCmdLineAry = new char*[ nParams+1 ]; osl_getExecutableFile( &aParam.pData ); osl_getSystemPathFromFileURL( aParam.pData, &aBin.pData ); pCmdLineAry[0] = g_strdup( OUStringToOString( aBin, aEnc ).getStr() ); for (i=0; i 0 ) { rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc); g_set_prgname( aPrgName.getStr()); } // init gtk/gdk gtk_init_check( &nParams, &pCmdLineAry ); //gtk_init_check sets XError/XIOError handlers, we want our own one m_aOrigGTKXIOErrorHandler = XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); PushXErrorLevel( !!getenv( "SAL_IGNOREXERRORS" ) ); for (i = 0; i < nParams; i++ ) g_free( pCmdLineAry[i] ); delete [] pCmdLineAry; #if OSL_DEBUG_LEVEL > 1 if (g_getenv ("SAL_DEBUG_UPDATES")) gdk_window_set_debug_updates (TRUE); #endif pGdkDisp = gdk_display_get_default(); if ( !pGdkDisp ) { rtl::OUString aProgramFileURL; osl_getExecutableFile( &aProgramFileURL.pData ); rtl::OUString aProgramSystemPath; osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData); rtl::OString aProgramName = rtl::OUStringToOString( aProgramSystemPath, osl_getThreadTextEncoding() ); fprintf( stderr, "%s X11 error: Can't open display: %s\n", aProgramName.getStr(), aDisplay.getStr()); fprintf( stderr, " Set DISPLAY environment variable, use -display option\n"); fprintf( stderr, " or check permissions of your X-Server\n"); fprintf( stderr, " (See \"man X\" resp. \"man xhost\" for details)\n"); fflush( stderr ); exit(0); } /* * if a -display switch was used, we need * to set the environment accoringly since * the clipboard build another connection * to the xserver using $DISPLAY */ rtl::OUString envVar(RTL_CONSTASCII_USTRINGPARAM("DISPLAY")); const gchar *name = gdk_display_get_name( pGdkDisp ); rtl::OUString envValue(name, strlen(name), aEnc); osl_setEnvironment(envVar.pData, envValue.pData); Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp ); m_pGtkSalDisplay = new GtkSalDisplay( pGdkDisp ); gdk_window_add_filter( NULL, call_filterGdkEvent, m_pGtkSalDisplay ); PushXErrorLevel( true ); SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp ); XSync( pDisp, False ); pKbdExtension->UseExtension( ! HasXErrorOccured() ); PopXErrorLevel(); m_pGtkSalDisplay->SetKbdExtension( pKbdExtension ); g_signal_connect( G_OBJECT(gdk_keymap_get_default()), "keys_changed", G_CALLBACK(signalKeysChanged), m_pGtkSalDisplay ); // add signal handler to notify screen size changes int nScreens = gdk_display_get_n_screens( pGdkDisp ); for( int n = 0; n < nScreens; n++ ) { GdkScreen *pScreen = gdk_display_get_screen( pGdkDisp, n ); if( pScreen ) { g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), m_pGtkSalDisplay ); if( ! gtk_check_version( 2, 14, 0 ) ) // monitors-changed came in with 2.14, avoid an assertion g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), m_pGtkSalDisplay ); } } } extern "C" { gboolean call_timeoutFn(gpointer data) { return GtkXLib::timeoutFn(data); } } gboolean GtkXLib::timeoutFn(gpointer data) { SalData *pSalData = GetSalData(); GtkXLib *pThis = (GtkXLib *) data; pSalData->m_pInstance->GetYieldMutex()->acquire(); if( pThis->m_pTimeout ) { g_source_unref (pThis->m_pTimeout); pThis->m_pTimeout = NULL; } // Auto-restart immediately pThis->StartTimer( pThis->m_nTimeoutMS ); GetX11SalData()->Timeout(); pSalData->m_pInstance->GetYieldMutex()->release(); return FALSE; } void GtkXLib::StartTimer( sal_uLong nMS ) { m_nTimeoutMS = nMS; // for restarting if (m_pTimeout) { g_source_destroy (m_pTimeout); g_source_unref (m_pTimeout); } m_pTimeout = g_timeout_source_new (m_nTimeoutMS); // #i36226# timers should be executed with lower priority // than XEvents like in generic plugin g_source_set_priority( m_pTimeout, G_PRIORITY_LOW ); g_source_set_can_recurse (m_pTimeout, TRUE); g_source_set_callback (m_pTimeout, call_timeoutFn, (gpointer) this, NULL); g_source_attach (m_pTimeout, g_main_context_default ()); SalXLib::StartTimer( nMS ); } void GtkXLib::StopTimer() { SalXLib::StopTimer(); if (m_pTimeout) { g_source_destroy (m_pTimeout); g_source_unref (m_pTimeout); m_pTimeout = NULL; } } extern "C" { gboolean call_userEventFn( gpointer data ) { return GtkXLib::userEventFn( data ); } } gboolean GtkXLib::userEventFn(gpointer data) { gboolean bContinue; GtkXLib *pThis = (GtkXLib *) data; SalData *pSalData = GetSalData(); pSalData->m_pInstance->GetYieldMutex()->acquire(); pThis->m_pGtkSalDisplay->EventGuardAcquire(); if( !pThis->m_pGtkSalDisplay->HasMoreEvents() ) { if( pThis->m_pUserEvent ) { g_source_unref (pThis->m_pUserEvent); pThis->m_pUserEvent = NULL; } bContinue = FALSE; } else bContinue = TRUE; pThis->m_pGtkSalDisplay->EventGuardRelease(); pThis->m_pGtkSalDisplay->DispatchInternalEvent(); pSalData->m_pInstance->GetYieldMutex()->release(); return bContinue; } // hEventGuard_ held during this invocation void GtkXLib::PostUserEvent() { if( !m_pUserEvent ) // not pending anyway { m_pUserEvent = g_idle_source_new(); g_source_set_priority( m_pUserEvent, G_PRIORITY_HIGH ); g_source_set_can_recurse (m_pUserEvent, TRUE); g_source_set_callback (m_pUserEvent, call_userEventFn, (gpointer) this, NULL); g_source_attach (m_pUserEvent, g_main_context_default ()); } Wakeup(); } void GtkXLib::Wakeup() { g_main_context_wakeup( g_main_context_default () ); } void GtkXLib::Yield( bool bWait, bool bHandleAllCurrentEvents ) { /* #i33212# only enter g_main_context_iteration in one thread at any one * time, else one of them potentially will never end as long as there is * another thread in in there. Having only one yieldin thread actually dispatch * fits the vcl event model (see e.g. the generic plugin). */ bool bDispatchThread = false; gboolean wasEvent = FALSE; { // release YieldMutex (and re-acquire at block end) YieldMutexReleaser aReleaser; if( osl_tryToAcquireMutex( m_aDispatchMutex ) ) bDispatchThread = true; else if( ! bWait ) return; // someone else is waiting already, return if( bDispatchThread ) { int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; gboolean wasOneEvent = TRUE; while( nMaxEvents-- && wasOneEvent ) { wasOneEvent = g_main_context_iteration( NULL, FALSE ); if( wasOneEvent ) wasEvent = TRUE; } if( bWait && ! wasEvent ) wasEvent = g_main_context_iteration( NULL, TRUE ); } else if( bWait ) { /* #i41693# in case the dispatch thread hangs in join * for this thread the condition will never be set * workaround: timeout of 1 second a emergency exit */ // we are the dispatch thread osl_resetCondition( m_aDispatchCondition ); TimeValue aValue = { 1, 0 }; osl_waitCondition( m_aDispatchCondition, &aValue ); } } if( bDispatchThread ) { osl_releaseMutex( m_aDispatchMutex ); if( wasEvent ) osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields } } extern "C" { typedef struct { GSource source; GPollFD pollfd; GIOCondition condition; YieldFunc pending; YieldFunc handle; gpointer user_data; } SalWatch; static gboolean sal_source_prepare (GSource *source, gint *timeout) { SalWatch *watch = (SalWatch *)source; *timeout = -1; if (watch->pending && watch->pending (watch->pollfd.fd, watch->user_data)) { watch->pollfd.revents |= watch->condition; return TRUE; } return FALSE; } static gboolean sal_source_check (GSource *source) { SalWatch *watch = (SalWatch *)source; return watch->pollfd.revents & watch->condition; } static gboolean sal_source_dispatch (GSource *source, GSourceFunc, gpointer) { SalData *pSalData = GetSalData(); SalWatch *watch = (SalWatch *) source; pSalData->m_pInstance->GetYieldMutex()->acquire(); watch->handle (watch->pollfd.fd, watch->user_data); pSalData->m_pInstance->GetYieldMutex()->release(); return TRUE; } static void sal_source_finalize (GSource*) { } static GSourceFuncs sal_source_watch_funcs = { sal_source_prepare, sal_source_check, sal_source_dispatch, sal_source_finalize, NULL, NULL }; static GSource * sal_source_create_watch (int fd, GIOCondition condition, YieldFunc pending, YieldFunc handle, gpointer user_data) { GSource *source; SalWatch *watch; GMainContext *context = g_main_context_default (); source = g_source_new (&sal_source_watch_funcs, sizeof (SalWatch)); watch = (SalWatch *) source; watch->pollfd.fd = fd; watch->pollfd.events = condition; watch->condition = condition; watch->pending = pending; watch->handle = handle; watch->user_data = user_data; g_source_set_can_recurse (source, TRUE); g_source_add_poll (source, &watch->pollfd); g_source_attach (source, context); return source; } } // extern "C" void GtkXLib::Insert( int nFD, void *data, YieldFunc pending, YieldFunc, YieldFunc handle ) { GSource *source = sal_source_create_watch ( nFD, (GIOCondition) ((G_IO_IN|G_IO_PRI) | (G_IO_ERR|G_IO_HUP|G_IO_NVAL)), pending, handle, data ); m_aSources.push_back( source ); } void GtkXLib::Remove( int nFD ) { ::std::list< GSource * >::iterator it; for (it = m_aSources.begin(); it != m_aSources.end(); ++it) { SalWatch *watch = (SalWatch *) *it; if (watch->pollfd.fd == nFD) { m_aSources.erase( it ); g_source_destroy ((GSource *)watch); g_source_unref ((GSource *)watch); return; } } } /********************************************************************** * class GtkData * **********************************************************************/ GtkData::~GtkData() { } void GtkData::Init() { pXLib_ = new GtkXLib(); pXLib_->Init(); }