/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #if defined(FREEBSD) || defined(NETBSD) #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef GDK_WINDOWING_X11 # include #endif #include #include using namespace vcl_sal; /*************************************************************** * class GtkSalDisplay * ***************************************************************/ extern "C" { static GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event, GdkEvent* /*event*/, gpointer data ) { GtkSalDisplay *pDisplay = static_cast(data); return pDisplay->filterGdkEvent( sys_event ); } } GtkSalDisplay::GtkSalDisplay( GdkDisplay* pDisplay ) : m_pSys( GtkSalSystem::GetSingleton() ), m_pGdkDisplay( pDisplay ), m_bStartupCompleted( false ) { for(GdkCursor* & rpCsr : m_aCursors) rpCsr = nullptr; // FIXME: unify this with SalInst's filter too ? gdk_window_add_filter( nullptr, call_filterGdkEvent, this ); if ( getenv( "SAL_IGNOREXERRORS" ) ) GetGenericUnixSalData()->ErrorTrapPush(); // and leak the trap m_bX11Display = GDK_IS_X11_DISPLAY( m_pGdkDisplay ); gtk_widget_set_default_direction(AllSettings::GetLayoutRTL() ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR); } GtkSalDisplay::~GtkSalDisplay() { gdk_window_remove_filter( nullptr, call_filterGdkEvent, this ); if( !m_bStartupCompleted ) gdk_notify_startup_complete(); for(GdkCursor* & rpCsr : m_aCursors) if( rpCsr ) gdk_cursor_unref( rpCsr ); } extern "C" { static void signalScreenSizeChanged( GdkScreen* pScreen, gpointer data ) { GtkSalDisplay* pDisp = static_cast(data); pDisp->screenSizeChanged( pScreen ); } static void signalMonitorsChanged( GdkScreen* pScreen, gpointer data ) { GtkSalDisplay* pDisp = static_cast(data); pDisp->monitorsChanged( pScreen ); } } GdkFilterReturn GtkSalDisplay::filterGdkEvent( GdkXEvent* ) { (void) this; // loplugin:staticmethods //FIXME: implement filterGdkEvent ... return GDK_FILTER_CONTINUE; } void GtkSalDisplay::screenSizeChanged( GdkScreen const * pScreen ) { m_pSys->countScreenMonitors(); if (pScreen) emitDisplayChanged(); } void GtkSalDisplay::monitorsChanged( GdkScreen const * pScreen ) { m_pSys->countScreenMonitors(); if (pScreen) emitDisplayChanged(); } namespace { //cairo annoyingly won't take raw xbm data unless it fits //the required cairo stride unsigned char* ensurePaddedForCairo(const unsigned char *pXBM, int nWidth, int nHeight, int nStride) { unsigned char *pPaddedXBM = const_cast(pXBM); int bytes_per_row = (nWidth + 7) / 8; if (nStride != bytes_per_row) { pPaddedXBM = new unsigned char[nStride * nHeight]; for (int row = 0; row < nHeight; ++row) { memcpy(pPaddedXBM + (nStride * row), pXBM + (bytes_per_row * row), bytes_per_row); memset(pPaddedXBM + (nStride * row) + bytes_per_row, 0, nStride - bytes_per_row); } } return pPaddedXBM; } } GdkCursor* GtkSalDisplay::getFromXBM( const unsigned char *pBitmap, const unsigned char *pMask, int nWidth, int nHeight, int nXHot, int nYHot ) { cairo_surface_t *source = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); cairo_t *cr = cairo_create(source); cairo_set_source_rgba(cr, 1, 1, 1, 1); cairo_paint(cr); const int cairo_stride = cairo_format_stride_for_width(CAIRO_FORMAT_A1, nWidth); unsigned char *pPaddedXBM = ensurePaddedForCairo(pBitmap, nWidth, nHeight, cairo_stride); cairo_surface_t *xbm = cairo_image_surface_create_for_data( pPaddedXBM, CAIRO_FORMAT_A1, nWidth, nHeight, cairo_stride); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_mask_surface(cr, xbm, 0, 0); cairo_surface_destroy(xbm); cairo_destroy(cr); unsigned char *pPaddedMaskXBM = ensurePaddedForCairo(pMask, nWidth, nHeight, cairo_stride); cairo_surface_t *mask = cairo_image_surface_create_for_data( pPaddedMaskXBM, CAIRO_FORMAT_A1, nWidth, nHeight, cairo_stride); cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, nWidth, nHeight); cr = cairo_create(s); cairo_set_source_surface(cr, source, 0, 0); cairo_mask_surface(cr, mask, 0, 0); cairo_surface_destroy(mask); cairo_surface_destroy(source); cairo_destroy(cr); GdkCursor *cursor = gdk_cursor_new_from_surface(m_pGdkDisplay, s, nXHot, nYHot); cairo_surface_destroy(s); if (pPaddedMaskXBM != pMask) delete [] pPaddedMaskXBM; if (pPaddedXBM != pBitmap) delete [] pPaddedXBM; return cursor; } static unsigned char nullmask_bits[] = { 0x00, 0x00, 0x00, 0x00 }; static unsigned char nullcurs_bits[] = { 0x00, 0x00, 0x00, 0x00 }; #define MAKE_CURSOR( vcl_name, name ) \ case vcl_name: \ pCursor = getFromXBM( 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 ( !m_aCursors[ ePointerStyle ] ) { GdkCursor *pCursor = nullptr; switch( ePointerStyle ) { MAP_BUILTIN( PointerStyle::Arrow, GDK_LEFT_PTR ); MAP_BUILTIN( PointerStyle::Text, GDK_XTERM ); MAP_BUILTIN( PointerStyle::Help, GDK_QUESTION_ARROW ); MAP_BUILTIN( PointerStyle::Cross, GDK_CROSSHAIR ); MAP_BUILTIN( PointerStyle::Wait, GDK_WATCH ); MAP_BUILTIN( PointerStyle::NSize, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::SSize, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::WSize, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::ESize, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::NWSize, GDK_TOP_LEFT_CORNER ); MAP_BUILTIN( PointerStyle::NESize, GDK_TOP_RIGHT_CORNER ); MAP_BUILTIN( PointerStyle::SWSize, GDK_BOTTOM_LEFT_CORNER ); MAP_BUILTIN( PointerStyle::SESize, GDK_BOTTOM_RIGHT_CORNER ); MAP_BUILTIN( PointerStyle::WindowNSize, GDK_TOP_SIDE ); MAP_BUILTIN( PointerStyle::WindowSSize, GDK_BOTTOM_SIDE ); MAP_BUILTIN( PointerStyle::WindowWSize, GDK_LEFT_SIDE ); MAP_BUILTIN( PointerStyle::WindowESize, GDK_RIGHT_SIDE ); MAP_BUILTIN( PointerStyle::WindowNWSize, GDK_TOP_LEFT_CORNER ); MAP_BUILTIN( PointerStyle::WindowNESize, GDK_TOP_RIGHT_CORNER ); MAP_BUILTIN( PointerStyle::WindowSWSize, GDK_BOTTOM_LEFT_CORNER ); MAP_BUILTIN( PointerStyle::WindowSESize, GDK_BOTTOM_RIGHT_CORNER ); MAP_BUILTIN( PointerStyle::HSizeBar, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::VSizeBar, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::RefHand, GDK_HAND2 ); MAP_BUILTIN( PointerStyle::Hand, GDK_HAND2 ); MAP_BUILTIN( PointerStyle::Pen, GDK_PENCIL ); MAP_BUILTIN( PointerStyle::HSplit, GDK_SB_H_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::VSplit, GDK_SB_V_DOUBLE_ARROW ); MAP_BUILTIN( PointerStyle::Move, GDK_FLEUR ); MAKE_CURSOR( PointerStyle::Null, null ); MAKE_CURSOR( PointerStyle::Magnify, magnify_ ); MAKE_CURSOR( PointerStyle::Fill, fill_ ); MAKE_CURSOR( PointerStyle::MoveData, movedata_ ); MAKE_CURSOR( PointerStyle::CopyData, copydata_ ); MAKE_CURSOR( PointerStyle::MoveFile, movefile_ ); MAKE_CURSOR( PointerStyle::CopyFile, copyfile_ ); MAKE_CURSOR( PointerStyle::MoveFiles, movefiles_ ); MAKE_CURSOR( PointerStyle::CopyFiles, copyfiles_ ); MAKE_CURSOR( PointerStyle::NotAllowed, nodrop_ ); MAKE_CURSOR( PointerStyle::Rotate, rotate_ ); MAKE_CURSOR( PointerStyle::HShear, hshear_ ); MAKE_CURSOR( PointerStyle::VShear, vshear_ ); MAKE_CURSOR( PointerStyle::DrawLine, drawline_ ); MAKE_CURSOR( PointerStyle::DrawRect, drawrect_ ); MAKE_CURSOR( PointerStyle::DrawPolygon, drawpolygon_ ); MAKE_CURSOR( PointerStyle::DrawBezier, drawbezier_ ); MAKE_CURSOR( PointerStyle::DrawArc, drawarc_ ); MAKE_CURSOR( PointerStyle::DrawPie, drawpie_ ); MAKE_CURSOR( PointerStyle::DrawCircleCut, drawcirclecut_ ); MAKE_CURSOR( PointerStyle::DrawEllipse, drawellipse_ ); MAKE_CURSOR( PointerStyle::DrawConnect, drawconnect_ ); MAKE_CURSOR( PointerStyle::DrawText, drawtext_ ); MAKE_CURSOR( PointerStyle::Mirror, mirror_ ); MAKE_CURSOR( PointerStyle::Crook, crook_ ); MAKE_CURSOR( PointerStyle::Crop, crop_ ); MAKE_CURSOR( PointerStyle::MovePoint, movepoint_ ); MAKE_CURSOR( PointerStyle::MoveBezierWeight, movebezierweight_ ); MAKE_CURSOR( PointerStyle::DrawFreehand, drawfreehand_ ); MAKE_CURSOR( PointerStyle::DrawCaption, drawcaption_ ); MAKE_CURSOR( PointerStyle::LinkData, linkdata_ ); MAKE_CURSOR( PointerStyle::MoveDataLink, movedlnk_ ); MAKE_CURSOR( PointerStyle::CopyDataLink, copydlnk_ ); MAKE_CURSOR( PointerStyle::LinkFile, linkfile_ ); MAKE_CURSOR( PointerStyle::MoveFileLink, moveflnk_ ); MAKE_CURSOR( PointerStyle::CopyFileLink, copyflnk_ ); MAKE_CURSOR( PointerStyle::Chart, chart_ ); MAKE_CURSOR( PointerStyle::Detective, detective_ ); MAKE_CURSOR( PointerStyle::PivotCol, pivotcol_ ); MAKE_CURSOR( PointerStyle::PivotRow, pivotrow_ ); MAKE_CURSOR( PointerStyle::PivotField, pivotfld_ ); MAKE_CURSOR( PointerStyle::PivotDelete, pivotdel_ ); MAKE_CURSOR( PointerStyle::Chain, chain_ ); MAKE_CURSOR( PointerStyle::ChainNotAllowed, chainnot_ ); MAKE_CURSOR( PointerStyle::AutoScrollN, asn_ ); MAKE_CURSOR( PointerStyle::AutoScrollS, ass_ ); MAKE_CURSOR( PointerStyle::AutoScrollW, asw_ ); MAKE_CURSOR( PointerStyle::AutoScrollE, ase_ ); MAKE_CURSOR( PointerStyle::AutoScrollNW, asnw_ ); MAKE_CURSOR( PointerStyle::AutoScrollNE, asne_ ); MAKE_CURSOR( PointerStyle::AutoScrollSW, assw_ ); MAKE_CURSOR( PointerStyle::AutoScrollSE, asse_ ); MAKE_CURSOR( PointerStyle::AutoScrollNS, asns_ ); MAKE_CURSOR( PointerStyle::AutoScrollWE, aswe_ ); MAKE_CURSOR( PointerStyle::AutoScrollNSWE, asnswe_ ); MAKE_CURSOR( PointerStyle::TextVertical, vertcurs_ ); // #i32329# MAKE_CURSOR( PointerStyle::TabSelectS, tblsels_ ); MAKE_CURSOR( PointerStyle::TabSelectE, tblsele_ ); MAKE_CURSOR( PointerStyle::TabSelectSE, tblselse_ ); MAKE_CURSOR( PointerStyle::TabSelectW, tblselw_ ); MAKE_CURSOR( PointerStyle::TabSelectSW, tblselsw_ ); MAKE_CURSOR( PointerStyle::HideWhitespace, hidewhitespace_ ); MAKE_CURSOR( PointerStyle::ShowWhitespace, showwhitespace_ ); default: SAL_WARN( "vcl.gtk", "pointer " << static_cast(ePointerStyle) << "not implemented" ); 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 = nullptr; return 0; } if( m_pCapture ) { if( pFrame == m_pCapture ) return 1; static_cast(m_pCapture)->grabPointer( FALSE ); } m_pCapture = pFrame; pFrame->grabPointer( TRUE ); return 1; } /********************************************************************** * class GtkSalData * **********************************************************************/ GtkSalData::GtkSalData( SalInstance *pInstance ) : GenericUnixSalData( SAL_DATA_GTK3, pInstance ) , m_aDispatchMutex() , m_aDispatchCondition() , m_pDocumentFocusListener(nullptr) { m_pUserEvent = nullptr; } #if defined(GDK_WINDOWING_X11) static XIOErrorHandler aOrigXIOErrorHandler = nullptr; extern "C" { static int XIOErrorHdl(Display *) { fprintf(stderr, "X IO Error\n"); _exit(1); // avoid crashes in unrelated threads that still run while atexit // handlers are in progress } } #endif GtkSalData::~GtkSalData() { Yield( true, true ); g_warning ("TESTME: We used to have a stop-timer here, but the central code should do this"); // sanity check: at this point nobody should be yielding, but wake them // up anyway before the condition they're waiting on gets destroyed. m_aDispatchCondition.set(); osl::MutexGuard g( m_aDispatchMutex ); if (m_pUserEvent) { g_source_destroy (m_pUserEvent); g_source_unref (m_pUserEvent); m_pUserEvent = nullptr; } #if defined(GDK_WINDOWING_X11) if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) XSetIOErrorHandler(aOrigXIOErrorHandler); #endif } void GtkSalData::Dispose() { deInitNWF(); } /// Allows events to be processed, returns true if we processed an event. bool GtkSalData::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 there. Having only one yielding thread actually dispatch * fits the vcl event model (see e.g. the generic plugin). */ bool bDispatchThread = false; bool bWasEvent = false; { // release YieldMutex (and re-acquire at block end) SolarMutexReleaser aReleaser; if( m_aDispatchMutex.tryToAcquire() ) bDispatchThread = true; else if( ! bWait ) { return false; // someone else is waiting already, return } if( bDispatchThread ) { int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1; gboolean wasOneEvent = TRUE; while( nMaxEvents-- && wasOneEvent ) { wasOneEvent = g_main_context_iteration( nullptr, bWait && !bWasEvent ); if( wasOneEvent ) bWasEvent = true; } if (m_aException) std::rethrow_exception(m_aException); } 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 m_aDispatchCondition.reset(); m_aDispatchCondition.wait(std::chrono::seconds(1)); } } if( bDispatchThread ) { m_aDispatchMutex.release(); if( bWasEvent ) m_aDispatchCondition.set(); // trigger non dispatch thread yields } return bWasEvent; } void GtkSalData::Init() { SAL_INFO( "vcl.gtk", "GtkMainloop::Init()" ); /* * open connection to X11 Display * try in this order: * o -display command line parameter, * o $DISPLAY environment variable * o default display */ GdkDisplay *pGdkDisp = nullptr; // is there a -display command line parameter? rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); int nParams = osl_getCommandArgCount(); OString aDisplay; 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 (int i = 0; i < nParams; ++i) { osl_getCommandArg(i, &aParam.pData ); OString aBParam( OUStringToOString( aParam, aEnc ) ); if( aParam == "-display" || aParam == "--display" ) { pCmdLineAry[i+1] = g_strdup( "--display" ); osl_getCommandArg(i+1, &aParam.pData ); aDisplay = OUStringToOString( aParam, aEnc ); } else pCmdLineAry[i+1] = g_strdup( aBParam.getStr() ); } // add executable nParams++; g_set_application_name(SalGenericSystem::getFrameClassName()); // Set consistent name of the root accessible OUString aAppName = Application::GetAppName(); if( !aAppName.isEmpty() ) { OString aPrgName = OUStringToOString(aAppName, aEnc); g_set_prgname(aPrgName.getStr()); } // init gtk/gdk gtk_init_check( &nParams, &pCmdLineAry ); gdk_error_trap_push(); for (int 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 ) { OUString aProgramFileURL; osl_getExecutableFile( &aProgramFileURL.pData ); OUString aProgramSystemPath; osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData); OString aProgramName = 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 defined(GDK_WINDOWING_X11) if (GDK_IS_X11_DISPLAY(pGdkDisp)) aOrigXIOErrorHandler = XSetIOErrorHandler(XIOErrorHdl); #endif GtkSalDisplay *pDisplay = new GtkSalDisplay( pGdkDisp ); SetDisplay( pDisplay ); //FIXME: unwind keyboard extension bits // 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 ) { pDisplay->screenSizeChanged( pScreen ); pDisplay->monitorsChanged( pScreen ); g_signal_connect( G_OBJECT(pScreen), "size-changed", G_CALLBACK(signalScreenSizeChanged), pDisplay ); g_signal_connect( G_OBJECT(pScreen), "monitors-changed", G_CALLBACK(signalMonitorsChanged), GetGtkDisplay() ); } } } void GtkSalData::ErrorTrapPush() { gdk_error_trap_push (); } bool GtkSalData::ErrorTrapPop( bool bIgnoreError ) { if (bIgnoreError) { gdk_error_trap_pop_ignored (); // faster return false; } return gdk_error_trap_pop () != 0; } #if !GLIB_CHECK_VERSION(2,32,0) #define G_SOURCE_REMOVE FALSE #endif extern "C" { struct SalGtkTimeoutSource { GSource aParent; GTimeVal aFireTime; GtkSalTimer *pInstance; }; static void sal_gtk_timeout_defer( SalGtkTimeoutSource *pTSource ) { g_get_current_time( &pTSource->aFireTime ); g_time_val_add( &pTSource->aFireTime, pTSource->pInstance->m_nTimeoutMS * 1000 ); } static gboolean sal_gtk_timeout_expired( SalGtkTimeoutSource *pTSource, gint *nTimeoutMS, GTimeVal const *pTimeNow ) { glong nDeltaSec = pTSource->aFireTime.tv_sec - pTimeNow->tv_sec; glong nDeltaUSec = pTSource->aFireTime.tv_usec - pTimeNow->tv_usec; if( nDeltaSec < 0 || ( nDeltaSec == 0 && nDeltaUSec < 0) ) { *nTimeoutMS = 0; return TRUE; } if( nDeltaUSec < 0 ) { nDeltaUSec += 1000000; nDeltaSec -= 1; } // if the clock changes backwards we need to cope ... if( static_cast(nDeltaSec) > 1 + ( pTSource->pInstance->m_nTimeoutMS / 1000 ) ) { sal_gtk_timeout_defer( pTSource ); return TRUE; } *nTimeoutMS = MIN( G_MAXINT, ( nDeltaSec * 1000 + (nDeltaUSec + 999) / 1000 ) ); return *nTimeoutMS == 0; } static gboolean sal_gtk_timeout_prepare( GSource *pSource, gint *nTimeoutMS ) { SalGtkTimeoutSource *pTSource = reinterpret_cast(pSource); GTimeVal aTimeNow; g_get_current_time( &aTimeNow ); return sal_gtk_timeout_expired( pTSource, nTimeoutMS, &aTimeNow ); } static gboolean sal_gtk_timeout_check( GSource *pSource ) { SalGtkTimeoutSource *pTSource = reinterpret_cast(pSource); GTimeVal aTimeNow; g_get_current_time( &aTimeNow ); return ( pTSource->aFireTime.tv_sec < aTimeNow.tv_sec || ( pTSource->aFireTime.tv_sec == aTimeNow.tv_sec && pTSource->aFireTime.tv_usec < aTimeNow.tv_usec ) ); } static gboolean sal_gtk_timeout_dispatch( GSource *pSource, GSourceFunc, gpointer ) { SalGtkTimeoutSource *pTSource = reinterpret_cast(pSource); if( !pTSource->pInstance ) return FALSE; SolarMutexGuard aGuard; sal_gtk_timeout_defer( pTSource ); ImplSVData* pSVData = ImplGetSVData(); if( pSVData->maSchedCtx.mpSalTimer ) pSVData->maSchedCtx.mpSalTimer->CallCallback(); return G_SOURCE_REMOVE; } static GSourceFuncs sal_gtk_timeout_funcs = { sal_gtk_timeout_prepare, sal_gtk_timeout_check, sal_gtk_timeout_dispatch, nullptr, nullptr, nullptr }; } static SalGtkTimeoutSource * create_sal_gtk_timeout( GtkSalTimer *pTimer ) { GSource *pSource = g_source_new( &sal_gtk_timeout_funcs, sizeof( SalGtkTimeoutSource ) ); SalGtkTimeoutSource *pTSource = reinterpret_cast(pSource); pTSource->pInstance = pTimer; // #i36226# timers should be executed with lower priority // than XEvents like in generic plugin g_source_set_priority( pSource, G_PRIORITY_LOW ); g_source_set_can_recurse( pSource, TRUE ); g_source_set_callback( pSource, /* unused dummy */ g_idle_remove_by_data, nullptr, nullptr ); g_source_attach( pSource, g_main_context_default() ); #ifdef DBG_UTIL g_source_set_name( pSource, "VCL timeout source" ); #endif sal_gtk_timeout_defer( pTSource ); return pTSource; } GtkSalTimer::GtkSalTimer() : m_pTimeout(nullptr) , m_nTimeoutMS(0) { } GtkSalTimer::~GtkSalTimer() { GtkInstance *pInstance = static_cast(GetSalData()->m_pInstance); pInstance->RemoveTimer(); Stop(); } bool GtkSalTimer::Expired() { if( !m_pTimeout || g_source_is_destroyed( &m_pTimeout->aParent ) ) return false; gint nDummy = 0; GTimeVal aTimeNow; g_get_current_time( &aTimeNow ); return !!sal_gtk_timeout_expired( m_pTimeout, &nDummy, &aTimeNow); } void GtkSalTimer::Start( sal_uLong nMS ) { // glib is not 64bit safe in this regard. assert( nMS <= G_MAXINT ); if ( nMS > G_MAXINT ) nMS = G_MAXINT; m_nTimeoutMS = nMS; // for restarting Stop(); // FIXME: ideally re-use an existing m_pTimeout m_pTimeout = create_sal_gtk_timeout( this ); } void GtkSalTimer::Stop() { if( m_pTimeout ) { g_source_destroy( &m_pTimeout->aParent ); g_source_unref( &m_pTimeout->aParent ); m_pTimeout = nullptr; } } extern "C" { static gboolean call_userEventFn( void *data ) { SolarMutexGuard aGuard; const SalGenericDisplay *pDisplay = GetGenericUnixSalData()->GetDisplay(); if ( pDisplay ) { GtkSalDisplay *pThisDisplay = static_cast(data)->GetGtkDisplay(); assert(static_cast(pThisDisplay) == pDisplay); pThisDisplay->DispatchInternalEvent(); } return TRUE; } } void GtkSalData::TriggerUserEventProcessing() { if (m_pUserEvent) g_main_context_wakeup (nullptr); // really needed ? else // nothing pending anyway { m_pUserEvent = g_idle_source_new(); // tdf#110737 set user-events to a lower priority than system redraw // events, which is G_PRIORITY_HIGH_IDLE + 20, so presentations // queue-redraw has a chance to be fulfilled g_source_set_priority (m_pUserEvent, G_PRIORITY_HIGH_IDLE + 30); g_source_set_can_recurse (m_pUserEvent, TRUE); g_source_set_callback (m_pUserEvent, call_userEventFn, static_cast(this), nullptr); g_source_attach (m_pUserEvent, g_main_context_default ()); } } void GtkSalData::TriggerAllUserEventsProcessed() { assert( m_pUserEvent ); g_source_destroy( m_pUserEvent ); g_source_unref( m_pUserEvent ); m_pUserEvent = nullptr; } void GtkSalDisplay::TriggerUserEventProcessing() { GetGtkSalData()->TriggerUserEventProcessing(); } void GtkSalDisplay::TriggerAllUserEventsProcessed() { GetGtkSalData()->TriggerAllUserEventsProcessed(); } GtkWidget* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow) const { for (auto pSalFrame : m_aFrames ) { const SystemEnvData* pEnvData = pSalFrame->GetSystemData(); if (pEnvData->aWindow == hWindow) return GTK_WIDGET(pEnvData->pWidget); } return nullptr; } void GtkSalDisplay::deregisterFrame( SalFrame* pFrame ) { if( m_pCapture == pFrame ) { static_cast(m_pCapture)->grabPointer( FALSE ); m_pCapture = nullptr; } SalGenericDisplay::deregisterFrame( pFrame ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ e-3-6-6'>libreoffice-3-6-6 LibreOffice 核心代码仓库文档基金会
summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2024-05-10loplugin:ostr in reportdesignNoel Grandin
Change-Id: I49d112d1a068ff265aa2242e62f53919f43fa15c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167436 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2022-08-18Move tools/diagnose_ex.h to comphelper/diagnose_ex.hxxStephan Bergmann
...so that its TOOLS_WARN_EXCEPTION can be used in comphelper/source/misc/logging.cxx in a follow-up commit. (And while at it, rename from diangose_ex.h to the more appropriate diagnose_ex.hxx. The comphelper module is sufficiently low-level for this immediate use case, so use that at least for now; o3tl might be even more suitable but doesn't have a Library until now. Also, for the immediate use case it would have sufficed to only break DbgGetCaughtException, exceptionToString, TOOLS_WARN_EXCEPTION, TOOLS_WARN_EXCEPTION_IF, and TOOLS_INFO_EXCEPTION out of include/tools/diagnose_ex.h into an additional new include/comphelper/diagnose_ex.hxx, but its probably easier overall to just move the complete include file as is.) Change-Id: I9f3222d4ccf1a9ac29d7eb9ba1530d53e2affaee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/138451 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2022-05-04Just use Any ctor instead of makeAny in reportdesignStephan Bergmann
Change-Id: If8b6f8f7facf36f740b2e1773e923e28d8c85552 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133792 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2021-10-30Prepare for removal of non-const operator[] from Sequence in reportdesignMike Kaganski
Change-Id: I7631aeb90bf224ba7a00025df6e3fa444b216a42 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124380 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
2021-02-16loplugin:referencecasting in reportdesignNoel
Also, I needed to add castToXInterface() to the upcasting Reference::Reference constructor, to resolve ambiguity in casting to XInterface. Change-Id: Ica60190bc842444c37de56407b586aa267f08372 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110890 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2020-05-05tdf#42949 Fix IWYU warnings in reportdesign/*/*cxxGabor Kelemen
Found with bin/find-unneeded-includes Only removal proposals are dealt with here. Change-Id: Ica1a10a8f8fff7c3780adcc30b2c8d0e385b1326 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93307 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
2020-04-02loplugin:flatten in reportdesignNoel Grandin
Change-Id: I6d8b2730cede4453e7afd581cc24ed101ca6c81b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91557 Tested-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2020-01-28New loplugin:unsignedcompareStephan Bergmann
"Find explicit casts from signed to unsigned integer in comparison against unsigned integer, where the cast is presumably used to avoid warnings about signed vs. unsigned comparisons, and could thus be replaced with o3tl::make_unsigned for clairty." (compilerplugins/clang/unsignedcompare.cxx) o3tl::make_unsigned requires its argument to be non-negative, and there is a chance that some original code like static_cast<sal_uInt32>(n) >= c used the explicit cast to actually force a (potentially negative) value of sal_Int32 to be interpreted as an unsigned sal_uInt32, rather than using the cast to avoid a false "signed vs. unsigned comparison" warning in a case where n is known to be non-negative. It appears that restricting this plugin to non- equality comparisons (<, >, <=, >=) and excluding equality comparisons (==, !=) is a useful heuristic to avoid such false positives. The only remainging false positive I found was 0288c8ffecff4956a52b9147d441979941e8b87f "Rephrase cast from sal_Int32 to sal_uInt32". But which of course does not mean that there were no further false positivies that I missed. So this commit may accidentally introduce some false hits of the assert in o3tl::make_unsigned. At least, it passed a full (Linux ASan+UBSan --enable-dbgutil) `make check && make screenshot`. It is by design that o3tl::make_unsigned only accepts signed integer parameter types (and is not defined as a nop for unsigned ones), to avoid unnecessary uses which would in general be suspicious. But the STATIC_ARRAY_SELECT macro in include/oox/helper/helper.hxx is used with both signed and unsigned types, so needs a little oox::detail::make_unsigned helper function for now. (The ultimate fix being to get rid of the macro in the first place.) Change-Id: Ia4adc9f44c70ad1dfd608784cac39ee922c32175 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/87556 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2019-12-03remove some useless comment linesNoel Grandin
which merely announce that the next declaration is a class Change-Id: Ifdb1398bcd99816b13e0b3769b46d0562bfbc1dc Reviewed-on: https://gerrit.libreoffice.org/84229 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2019-10-19loplugin:unusedfieldsNoel Grandin
Change-Id: I7dd5fc3d53df63fd2ee2caa71586f0f5e13f187e Reviewed-on: https://gerrit.libreoffice.org/81078 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2019-10-13weld ConditionalFormattingDialogCaolán McNamara
Change-Id: I87c03555c5555b12a1be997e368a96d9b07d2b63 Reviewed-on: https://gerrit.libreoffice.org/80689 Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
2019-02-12Simplify containers iterations in reportdesign, sal, saxArkadiy Illarionov
Use range-based loop or replace with STL functions Change-Id: If6b734dab12a7298fce16003d3d175305fbe798d Reviewed-on: https://gerrit.libreoffice.org/67701 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2018-04-03pass area param to DBG_UNHANDLED_EXCEPTIONNoel Grandin
and update sallogareas plugin to enforce this Change-Id: Id0782c8a1f619372e10d931aec3c6a4743a4c86a Reviewed-on: https://gerrit.libreoffice.org/52249 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2018-03-20drop unnecessary includesCaolán McNamara
Change-Id: I1a817d5575bbd57ecaa874a27158b9218e4210cc Reviewed-on: https://gerrit.libreoffice.org/51603 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
2018-03-02delete colordata.hxxNoel Grandin
move what we still need into color.hxx Change-Id: Ied7e31eb16468aa334c666b1499a6262f16a6350 Reviewed-on: https://gerrit.libreoffice.org/50561 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2018-02-01tdf#42949 Remove unneeded helpids.h headers (2/3)Gabor Kelemen
A side effect of the .ui migration is that we use a lot less HIDs in the code. A lot of files still contain helpids.h includes even if no actual HID is referenced. This cleans up directories r* - svx*. Found with: git grep helpids.h | cut -d : -f 1 | xargs grep -c HID_ | grep :0$ Change-Id: I81bdb80161b0207f5df651eb17c58caef44250d3 Reviewed-on: https://gerrit.libreoffice.org/46869 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Michael Stahl <mstahl@redhat.com>
2018-01-12More loplugin:cstylecast: reportdesignStephan Bergmann
auto-rewrite with <https://gerrit.libreoffice.org/#/c/47798/> "Enable loplugin:cstylecast for some more cases" plus solenv/clang-format/reformat-formatted-files Change-Id: I690ddd7eeb5fbac979292a382074e9b29c065416
2017-10-23loplugin:includeform: reportdesignStephan Bergmann
Change-Id: Ie531677be09c264ed1536ad2512e76f29ab46881
2017-07-21de-hrc various thingsCaolán McNamara
e.g. helpid[s].hrc -> helpids.h and insert include guards where missing move "ordinary" defines into .hxx files remove .hrc entries that are used as arguments to dialog factory when a dedicated method can be added instead Change-Id: I792fb8eb0adfaa63cf354e6e57401fc943e9196e
2017-07-21migrate to boost::gettextCaolán McNamara
* all .ui files go from <interface> to <interface domain="MODULE"> e.g. vcl * all .src files go away and the english source strings folded into the .hrc as NC_("context", "source string") * ResMgr is dropped in favour of std::locale imbued by boost::locale::generator pointed at matching MODULE .mo files * UIConfig translations are folded into the module .mo, so e.g. UIConfig_cui goes from l10n target to normal one, so the res/lang.zips of UI files go away * translation via Translation::get(hrc-define-key, imbued-std::locale) * python can now be translated with its inbuilt gettext support (we keep the name strings.hrc there to keep finding the .hrc file uniform) so magic numbers can go away there * java and starbasic components can be translated via the pre-existing css.resource.StringResourceWithLocation mechanism * en-US res files go away, their strings are now the .hrc keys in the source code * remaining .res files are replaced by .mo files * in .res/.ui-lang-zip files, the old scheme missing translations of strings results in inserting the english original so something can be found, now the standard fallback of using the english original from the source key is used, so partial translations shrink dramatically in size * extract .hrc strings with hrcex which backs onto xgettext -C --add-comments --keyword=NC_:1c,2 --from-code=UTF-8 --no-wrap * extract .ui strings with uiex which backs onto xgettext --add-comments --no-wrap * qtz for gettext translations is generated at runtime as ascii-ified crc32 of content + "|" + msgid * [API CHANGE] remove deprecated binary .res resouce loader related uno apis com::sun::star::resource::OfficeResourceLoader com::sun::star::resource::XResourceBundleLoader com::sun::star::resource::XResourceBundle when translating strings via uno apis com.sun.star.resource.StringResourceWithLocation can continue to be used Change-Id: Ia2594a2672b7301d9c3421fdf31b6cfe7f3f8d0a
2017-07-10teach unnecessaryparen loplugin about identifiersNoel Grandin
Change-Id: I5710b51e53779c222cec0bf08cd34bda330fec4b Reviewed-on: https://gerrit.libreoffice.org/39737 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
2016-12-09tdf#104105: fix Vcl lifecycle in CondFormat (reportdesign)Julien Nabet
Avoid this error: Window ( 7VclVBox()) with live children destroyed: N5rptui9ConditionE() * n by calling disposeAndClear on each element of m_aConditions m_aConditions is Conditions type Conditions type is ::std::vector< VclPtr<Condition> > See http://opengrok.libreoffice.org/xref/core/reportdesign/source/ui/inc/CondFormat.hxx#70 Change-Id: Ie99f8cdb5acd787892237787525d79f3231689db Reviewed-on: https://gerrit.libreoffice.org/31775 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Julien Nabet <serval2412@yahoo.fr>