diff options
Diffstat (limited to 'vcl/unx/gtk/app')
-rw-r--r-- | vcl/unx/gtk/app/gtkdata.cxx | 994 | ||||
-rw-r--r-- | vcl/unx/gtk/app/gtkinst.cxx | 352 | ||||
-rw-r--r-- | vcl/unx/gtk/app/gtksys.cxx | 96 | ||||
-rw-r--r-- | vcl/unx/gtk/app/makefile.mk | 76 |
4 files changed, 1518 insertions, 0 deletions
diff --git a/vcl/unx/gtk/app/gtkdata.cxx b/vcl/unx/gtk/app/gtkdata.cxx new file mode 100644 index 000000000000..d1e5c5954352 --- /dev/null +++ b/vcl/unx/gtk/app/gtkdata.cxx @@ -0,0 +1,994 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#define _SV_SALDATA_CXX + +// -=-= #includes =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +#include <unistd.h> +#include <fcntl.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <errno.h> +#include <poll.h> +#ifdef FREEBSD +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#endif +#include <plugins/gtk/gtkdata.hxx> +#include <plugins/gtk/gtkinst.hxx> +#include <plugins/gtk/gtkframe.hxx> +#include <salobj.h> +#include <osl/thread.h> +#include <osl/process.h> + +#include <tools/debug.hxx> +#include "i18n_im.hxx" +#include "i18n_xkb.hxx" +#include <wmadaptor.hxx> + +#include "../../unx/source/inc/salcursors.h" + +#include <vcl/svapp.hxx> + +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<GtkSalFrame*>(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<GtkSalFrame*>(*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<int>(m_aScreens.size()) ) + { + ScreenData& rSD = const_cast<ScreenData&>(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 ) +{ + 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<Rectangle>(); + for (gint i = 0; i < nMonitors; ++i) + { + GdkRectangle dest; + gdk_screen_get_monitor_geometry(pScreen, i, &dest); + 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" ); + } + } + } +} + +void GtkSalDisplay::initScreen( int nScreen ) const +{ + if( nScreen < 0 || nScreen >= static_cast<int>(m_aScreens.size()) ) + nScreen = m_nDefaultScreen; + ScreenData& rSD = const_cast<ScreenData&>(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<GtkSalFrame*>(*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( name##curs##_bits, 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<GtkSalFrame*>(pSFrame); + + if( !pFrame ) + { + if( m_pCapture ) + static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); + m_pCapture = NULL; + return 0; + } + + if( m_pCapture ) + { + if( pFrame == m_pCapture ) + return 1; + static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( FALSE ); + } + + m_pCapture = pFrame; + static_cast<GtkSalFrame*>(pFrame)->grabPointer( TRUE ); + return 1; +} + +/*************************************************************************** + * class GtkXLib * + ***************************************************************************/ + +class GtkXLib : public SalXLib +{ + GtkSalDisplay *m_pGtkSalDisplay; + std::list<GSource *> m_aSources; + GSource *m_pTimeout; + GSource *m_pUserEvent; + oslMutex m_aDispatchMutex; + oslCondition m_aDispatchCondition; + +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( 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(); +} + +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 ); +} + +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<nParams; i++) + { + osl_getCommandArg(i, &aParam.pData ); + OString aBParam( OUStringToOString( aParam, aEnc ) ); + + if( aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" ) ) + { + pCmdLineAry[i+1] = g_strdup( "--display" ); + osl_getCommandArg(i+1, &aParam.pData ); + aDisplay = rtl::OUStringToOString( aParam, aEnc ); + } + else + pCmdLineAry[i+1] = g_strdup( aBParam.getStr() ); + } + // add executable + nParams++; + + g_set_application_name(X11SalData::getFrameClassName()); + + // Set consistant name of the root accessible + rtl::OUString aAppName = Application::GetAppName(); + if( aAppName.getLength() > 0 ) + { + rtl::OString aPrgName = rtl::OUStringToOString(aAppName, aEnc); + g_set_prgname(aPrgName); + } + + // init gtk/gdk + gtk_init_check( &nParams, &pCmdLineAry ); + + 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 + */ + char *pPutEnvIsBroken = g_strdup_printf( "DISPLAY=%s", + gdk_display_get_name( pGdkDisp ) ); + putenv( pPutEnvIsBroken ); + + Display *pDisp = gdk_x11_display_get_xdisplay( pGdkDisp ); + + XSetIOErrorHandler ( (XIOErrorHandler)X11SalData::XIOErrorHdl ); + XSetErrorHandler ( (XErrorHandler)X11SalData::XErrorHdl ); + + 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( 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; + { + // release YieldMutex (and re-acquire at block end) + YieldMutexReleaser aReleaser; + if( osl_tryToAcquireMutex( m_aDispatchMutex ) ) + { + // we are the dispatch thread + osl_resetCondition( m_aDispatchCondition ); + bDispatchThread = true; + } + else if( ! bWait ) + return; // someone else is waiting already, return + + + if( bDispatchThread ) + { + int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; + gboolean wasEvent = FALSE, wasOneEvent = TRUE; + while( nMaxEvents-- && wasOneEvent ) + { + wasOneEvent = g_main_context_iteration( NULL, FALSE ); + if( wasOneEvent ) + wasEvent = TRUE; + } + if( bWait && ! wasEvent ) + g_main_context_iteration( NULL, TRUE ); + } + else if( userEventFn( this ) ) + { + /* #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 + */ + TimeValue aValue; + aValue.Seconds = 1; + aValue.Nanosec = 0; + osl_waitCondition( m_aDispatchCondition, &aValue ); + } + } + + if( bDispatchThread ) + { + osl_releaseMutex( m_aDispatchMutex ); + osl_setCondition( m_aDispatchCondition ); // trigger non dispatch thread yields + osl_resetCondition( m_aDispatchCondition ); + } +} + +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(); +} diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx new file mode 100644 index 000000000000..68617c8c16be --- /dev/null +++ b/vcl/unx/gtk/app/gtkinst.cxx @@ -0,0 +1,352 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <osl/module.h> +#include <plugins/gtk/gtkdata.hxx> +#include <plugins/gtk/gtkinst.hxx> +#include <salframe.h> +#include <salobj.h> +#include <plugins/gtk/gtkframe.hxx> +#include <plugins/gtk/gtkobject.hxx> +#include <plugins/gtk/atkbridge.hxx> + +#include <rtl/strbuf.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +#include <dlfcn.h> +#include <fcntl.h> +#include <unistd.h> + +GtkHookedYieldMutex::GtkHookedYieldMutex() +{ +} + +/* + * These methods always occur in pairs + * A ThreadsEnter is followed by a ThreadsLeave + * We need to queue up the recursive lock count + * for each pair, so we can accurately restore + * it later. + */ +void GtkHookedYieldMutex::ThreadsEnter() +{ + acquire(); + if( !aYieldStack.empty() ) + { /* Previously called ThreadsLeave() */ + ULONG nCount = aYieldStack.front(); + aYieldStack.pop_front(); + while( nCount-- > 1 ) + acquire(); + } +} + +void GtkHookedYieldMutex::ThreadsLeave() +{ + aYieldStack.push_front( mnCount ); + +#if OSL_DEBUG_LEVEL > 1 + if( mnThreadId && + mnThreadId != NAMESPACE_VOS(OThread)::getCurrentIdentifier()) + fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n"); +#endif + + while( mnCount > 1 ) + release(); + release(); +} + +void GtkHookedYieldMutex::acquire() +{ + SalYieldMutex::acquire(); +} + +void GtkHookedYieldMutex::release() +{ + SalYieldMutex::release(); +} + +extern "C" +{ + #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex()) + static void GdkThreadsEnter( void ) + { + GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX(); + pYieldMutex->ThreadsEnter(); + } + static void GdkThreadsLeave( void ) + { + GtkHookedYieldMutex *pYieldMutex = GET_YIELD_MUTEX(); + pYieldMutex->ThreadsLeave(); + } + static bool hookLocks( oslModule pModule ) + { + typedef void (*GdkLockFn) (GCallback enter_fn, GCallback leave_fn); + + GdkLockFn gdk_threads_set_lock_functions = + (GdkLockFn) osl_getAsciiFunctionSymbol( pModule, "gdk_threads_set_lock_functions" ); + if ( !gdk_threads_set_lock_functions ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "Failed to hook gdk threads locks\n" ); +#endif + return false; + } + + gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "Hooked gdk threads locks\n" ); +#endif + return true; + } + + VCL_DLLPUBLIC SalInstance* create_SalInstance( oslModule pModule ) + { + /* #i92121# workaround deadlocks in the X11 implementation + */ + static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); + /* #i90094# + from now on we know that an X connection will be + established, so protect X against itself + */ + if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) + XInitThreads(); + + const gchar* pVersion = gtk_check_version( 2, 2, 0 ); + if( pVersion ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "gtk version conflict: %s\n", pVersion ); +#endif + return NULL; + } + + GtkYieldMutex *pYieldMutex; + + // init gdk thread protection + if ( !g_thread_supported() ) + g_thread_init( NULL ); + + if ( hookLocks( pModule ) ) + pYieldMutex = new GtkHookedYieldMutex(); + else + pYieldMutex = new GtkYieldMutex(); + + gdk_threads_init(); + + GtkInstance* pInstance = new GtkInstance( pYieldMutex ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance ); +#endif + + // initialize SalData + GtkData *pSalData = new GtkData(); + SetSalData( pSalData ); + pSalData->m_pInstance = pInstance; + pSalData->Init(); + pSalData->initNWF(); + + InitAtkBridge(); + + return pInstance; + } +} + +GtkInstance::~GtkInstance() +{ + DeInitAtkBridge(); +} + +SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, ULONG nStyle ) +{ + return new GtkSalFrame( pParent, nStyle ); +} + +SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, ULONG ) +{ + SalFrame* pFrame = new GtkSalFrame( pParentData ); + + return pFrame; +} + +SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, BOOL bShow ) +{ + // there is no method to set a visual for a GtkWidget + // so we need the X11SalObject in that case + if( pWindowData ) + return X11SalObject::CreateObject( pParent, pWindowData, bShow ); + + return new GtkSalObject( static_cast<GtkSalFrame*>(pParent), bShow ); +} + +extern "C" +{ + typedef void*(* getDefaultFnc)(); + typedef void(* addItemFnc)(void *, const char *); +} + +void GtkInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& rMimeType) +{ +#if GTK_CHECK_VERSION(2,10,0) + GtkRecentManager *manager = gtk_recent_manager_get_default (); + gtk_recent_manager_add_item (manager, rtl::OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8).getStr()); + (void)rMimeType; +#else + static getDefaultFnc sym_gtk_recent_manager_get_default = + (getDefaultFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_get_default" ); + + static addItemFnc sym_gtk_recent_manager_add_item = + (addItemFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_add_item"); + if (sym_gtk_recent_manager_get_default && sym_gtk_recent_manager_add_item) + { + sym_gtk_recent_manager_add_item(sym_gtk_recent_manager_get_default(), + rtl::OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8).getStr()); + } + else + X11SalInstance::AddToRecentDocumentList(rFileUrl, rMimeType); +#endif +} + +GtkYieldMutex::GtkYieldMutex() +{ +} + +void GtkYieldMutex::acquire() +{ + vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier(); + // protect member manipulation + OMutex::acquire(); + if( mnCount > 0 && mnThreadId == aCurrentThread ) + { + mnCount++; + OMutex::release(); + return; + } + OMutex::release(); + + // obtain gdk mutex + gdk_threads_enter(); + + // obtained gdk mutex, now lock count is one by definition + OMutex::acquire(); + mnCount = 1; + mnThreadId = aCurrentThread; + OMutex::release(); +} + +void GtkYieldMutex::release() +{ + vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier(); + // protect member manipulation + OMutex::acquire(); + // strange things happen, do nothing if we don't own the mutex + if( mnThreadId == aCurrentThread ) + { + mnCount--; + if( mnCount == 0 ) + { + gdk_threads_leave(); + mnThreadId = 0; + } + } + OMutex::release(); +} + +sal_Bool GtkYieldMutex::tryToAcquire() +{ + vos::OThread::TThreadIdentifier aCurrentThread = vos::OThread::getCurrentIdentifier(); + // protect member manipulation + OMutex::acquire(); + if( mnCount > 0 ) + { + if( mnThreadId == aCurrentThread ) + { + mnCount++; + OMutex::release(); + return sal_True; + } + else + { + OMutex::release(); + return sal_False; + } + } + OMutex::release(); + + // HACK: gdk_threads_mutex is private, we shouldn't use it. + // how to we do a try_lock without having a gdk_threads_try_enter ? + if( ! g_mutex_trylock( gdk_threads_mutex ) ) + return sal_False; + + // obtained gdk mutex, now lock count is one by definition + OMutex::acquire(); + mnCount = 1; + mnThreadId = aCurrentThread; + OMutex::release(); + + return sal_True; +} + +int GtkYieldMutex::Grab() +{ + // this MUST only be called by gdk/gtk callbacks: + // they are entered with gdk mutex locked; the mutex + // was unlocked by GtkYieldMutex befor yielding which + // is now locked again by gtk implicitly + + // obtained gdk mutex, now lock count is one by definition + OMutex::acquire(); + int nRet = mnCount; + if( mnCount == 0 ) // recursive else + mnThreadId = vos::OThread::getCurrentIdentifier(); +#if OSL_DEBUG_LEVEL > 1 + else if( mnThreadId != vos::OThread::getCurrentIdentifier() ) + { + fprintf( stderr, "Yield mutex grabbed in different thread !\n" ); + abort(); + } +#endif + mnCount = 1; + OMutex::release(); + return nRet; +} + +void GtkYieldMutex::Ungrab( int nGrabs ) +{ + // this MUST only be called when leaving the callback + // that locked the mutex with Grab() + OMutex::acquire(); + mnCount = nGrabs; + if( mnCount == 0 ) + mnThreadId = 0; + OMutex::release(); +} diff --git a/vcl/unx/gtk/app/gtksys.cxx b/vcl/unx/gtk/app/gtksys.cxx new file mode 100644 index 000000000000..272af20d0886 --- /dev/null +++ b/vcl/unx/gtk/app/gtksys.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <svunx.h> +#include <vcl/svdata.hxx> +#include <vcl/window.hxx> +#include <plugins/gtk/gtkinst.hxx> +#include <cstdio> +#include <gdk/gdk.h> +#include <gtk/gtk.h> +#include <X11/Xlib.h> + +SalSystem *GtkInstance::CreateSalSystem() +{ + return new GtkSalSystem(); +} + +GtkSalSystem::~GtkSalSystem() +{ +} + +int GtkSalSystem::ShowNativeDialog( const String& rTitle, + const String& rMessage, + const std::list< String >& rButtons, + int nDefButton ) +{ + + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData->mpIntroWindow ) + pSVData->mpIntroWindow->Hide(); + +#if OSL_DEBUG_LEVEL > 1 + std::fprintf( stderr, "GtkSalSystem::ShowNativeDialog\n"); +#endif + + ByteString aTitle( rTitle, RTL_TEXTENCODING_UTF8 ); + ByteString aMessage( rMessage, RTL_TEXTENCODING_UTF8 ); + + /* Create the dialogue */ + GtkWidget* mainwin = gtk_message_dialog_new + ( NULL, (GtkDialogFlags)0, GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, aMessage.GetBuffer(), NULL ); + gtk_window_set_title( GTK_WINDOW( mainwin ), aTitle.GetBuffer() ); + + gint nButtons = 0, nResponse; + + int nButton = 0; + for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it ) + { + ByteString aLabel( *it, RTL_TEXTENCODING_UTF8 ); + + if( nButton == nDefButton ) + { + gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons ); + gtk_dialog_set_default_response( GTK_DIALOG( mainwin ), nButtons ); + } + else + gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons ); + nButtons++; + } + + nResponse = gtk_dialog_run( GTK_DIALOG(mainwin) ); + if( nResponse == GTK_RESPONSE_NONE || nResponse == GTK_RESPONSE_DELETE_EVENT ) + nResponse = -1; + + gtk_widget_destroy( GTK_WIDGET(mainwin) ); + + return nResponse; +} diff --git a/vcl/unx/gtk/app/makefile.mk b/vcl/unx/gtk/app/makefile.mk new file mode 100644 index 000000000000..3e8cd750bf7a --- /dev/null +++ b/vcl/unx/gtk/app/makefile.mk @@ -0,0 +1,76 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=vcl +TARGET=gtkapp +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# workaround for makedepend hang +MKDEPENDSOLVER= + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile2.pmk + +# --- Files -------------------------------------------------------- + +.IF "$(GUIBASE)"!="unx" + +dummy: + @echo "Nothing to build for GUIBASE $(GUIBASE)" + +.ELSE # "$(GUIBASE)"!="unx" + +.IF "$(ENABLE_GTK)" != "" + +PKGCONFIG_MODULES=gtk+-2.0 +.INCLUDE : pkg_config.mk + +SLOFILES=\ + $(SLO)$/gtkdata.obj \ + $(SLO)$/gtkinst.obj \ + $(SLO)$/gtksys.obj + +EXCEPTIONSFILES=\ + $(SLO)$/gtkdata.obj\ + $(SLO)$/gtkinst.obj + +.ELSE # "$(ENABLE_GTK)" != "" + +dummy: + @echo GTK disabled - nothing to build +.ENDIF +.ENDIF # "$(GUIBASE)"!="unx" + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + +.INCLUDE : $(PRJ)$/util$/target.pmk |