1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #if defined(FREEBSD) || defined(NETBSD)
25 #include <sys/types.h>
28 #include <unx/gtk/gtkbackend.hxx>
29 #include <unx/gtk/gtkdata.hxx>
30 #include <unx/gtk/gtkinst.hxx>
31 #include <unx/gtk/gtkframe.hxx>
32 #include <bitmaps.hlst>
33 #include <cursor_hotspots.hxx>
34 #include <osl/thread.h>
35 #include <osl/process.h>
37 #include <vcl/svapp.hxx>
38 #include <sal/log.hxx>
44 using namespace vcl_sal
;
46 /***************************************************************
47 * class GtkSalDisplay *
48 ***************************************************************/
50 static GdkFilterReturn
call_filterGdkEvent( GdkXEvent
* sys_event
,
54 GtkSalDisplay
*pDisplay
= static_cast<GtkSalDisplay
*>(data
);
55 return pDisplay
->filterGdkEvent( sys_event
);
59 GtkSalDisplay::GtkSalDisplay( GdkDisplay
* pDisplay
) :
60 m_pSys( GtkSalSystem::GetSingleton() ),
61 m_pGdkDisplay( pDisplay
),
62 m_bStartupCompleted( false )
64 for(GdkCursor
* & rpCsr
: m_aCursors
)
67 // FIXME: unify this with SalInst's filter too ?
68 gdk_window_add_filter( nullptr, call_filterGdkEvent
, this );
70 if ( getenv( "SAL_IGNOREXERRORS" ) )
71 GetGenericUnixSalData()->ErrorTrapPush(); // and leak the trap
73 m_bX11Display
= DLSYM_GDK_IS_X11_DISPLAY( m_pGdkDisplay
);
75 gtk_widget_set_default_direction(AllSettings::GetLayoutRTL() ? GTK_TEXT_DIR_RTL
: GTK_TEXT_DIR_LTR
);
78 GtkSalDisplay::~GtkSalDisplay()
80 gdk_window_remove_filter( nullptr, call_filterGdkEvent
, this );
82 if( !m_bStartupCompleted
)
83 gdk_notify_startup_complete();
85 for(GdkCursor
* & rpCsr
: m_aCursors
)
87 gdk_cursor_unref( rpCsr
);
92 static void signalScreenSizeChanged( GdkScreen
* pScreen
, gpointer data
)
94 GtkSalDisplay
* pDisp
= static_cast<GtkSalDisplay
*>(data
);
95 pDisp
->screenSizeChanged( pScreen
);
98 static void signalMonitorsChanged( GdkScreen
* pScreen
, gpointer data
)
100 GtkSalDisplay
* pDisp
= static_cast<GtkSalDisplay
*>(data
);
101 pDisp
->monitorsChanged( pScreen
);
106 GdkFilterReturn
GtkSalDisplay::filterGdkEvent( GdkXEvent
* )
108 (void) this; // loplugin:staticmethods
109 //FIXME: implement filterGdkEvent ...
110 return GDK_FILTER_CONTINUE
;
113 void GtkSalDisplay::screenSizeChanged( GdkScreen
const * pScreen
)
115 m_pSys
->countScreenMonitors();
117 emitDisplayChanged();
120 void GtkSalDisplay::monitorsChanged( GdkScreen
const * pScreen
)
122 m_pSys
->countScreenMonitors();
124 emitDisplayChanged();
127 GdkCursor
* GtkSalDisplay::getFromSvg(OUString
const & name
, int nXHot
, int nYHot
)
129 GdkPixbuf
* pPixBuf
= load_icon_by_name(name
);
130 assert(pPixBuf
&& "missing image?");
133 guint nDefaultCursorSize
= gdk_display_get_default_cursor_size( m_pGdkDisplay
);
134 GdkPixbuf
* pScaledPixBuf
= gdk_pixbuf_scale_simple(pPixBuf
, nDefaultCursorSize
, nDefaultCursorSize
, GDK_INTERP_HYPER
);
135 g_object_unref(pPixBuf
);
136 GdkCursor
* pCursor
= gdk_cursor_new_from_pixbuf( m_pGdkDisplay
, pScaledPixBuf
, nXHot
, nYHot
);
140 #define MAKE_CURSOR( vcl_name, name, name2 ) \
142 pCursor = getFromSvg(name2, name##curs_x_hot, name##curs_y_hot); \
144 #define MAP_BUILTIN( vcl_name, gdk_name ) \
146 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
149 GdkCursor
*GtkSalDisplay::getCursor( PointerStyle ePointerStyle
)
151 if ( !m_aCursors
[ ePointerStyle
] )
153 GdkCursor
*pCursor
= nullptr;
155 switch( ePointerStyle
)
157 MAP_BUILTIN( PointerStyle::Arrow
, GDK_LEFT_PTR
);
158 MAP_BUILTIN( PointerStyle::Text
, GDK_XTERM
);
159 MAP_BUILTIN( PointerStyle::Help
, GDK_QUESTION_ARROW
);
160 MAP_BUILTIN( PointerStyle::Cross
, GDK_CROSSHAIR
);
161 MAP_BUILTIN( PointerStyle::Wait
, GDK_WATCH
);
163 MAP_BUILTIN( PointerStyle::NSize
, GDK_SB_V_DOUBLE_ARROW
);
164 MAP_BUILTIN( PointerStyle::SSize
, GDK_SB_V_DOUBLE_ARROW
);
165 MAP_BUILTIN( PointerStyle::WSize
, GDK_SB_H_DOUBLE_ARROW
);
166 MAP_BUILTIN( PointerStyle::ESize
, GDK_SB_H_DOUBLE_ARROW
);
168 MAP_BUILTIN( PointerStyle::NWSize
, GDK_TOP_LEFT_CORNER
);
169 MAP_BUILTIN( PointerStyle::NESize
, GDK_TOP_RIGHT_CORNER
);
170 MAP_BUILTIN( PointerStyle::SWSize
, GDK_BOTTOM_LEFT_CORNER
);
171 MAP_BUILTIN( PointerStyle::SESize
, GDK_BOTTOM_RIGHT_CORNER
);
173 MAP_BUILTIN( PointerStyle::WindowNSize
, GDK_TOP_SIDE
);
174 MAP_BUILTIN( PointerStyle::WindowSSize
, GDK_BOTTOM_SIDE
);
175 MAP_BUILTIN( PointerStyle::WindowWSize
, GDK_LEFT_SIDE
);
176 MAP_BUILTIN( PointerStyle::WindowESize
, GDK_RIGHT_SIDE
);
178 MAP_BUILTIN( PointerStyle::WindowNWSize
, GDK_TOP_LEFT_CORNER
);
179 MAP_BUILTIN( PointerStyle::WindowNESize
, GDK_TOP_RIGHT_CORNER
);
180 MAP_BUILTIN( PointerStyle::WindowSWSize
, GDK_BOTTOM_LEFT_CORNER
);
181 MAP_BUILTIN( PointerStyle::WindowSESize
, GDK_BOTTOM_RIGHT_CORNER
);
183 MAP_BUILTIN( PointerStyle::HSizeBar
, GDK_SB_H_DOUBLE_ARROW
);
184 MAP_BUILTIN( PointerStyle::VSizeBar
, GDK_SB_V_DOUBLE_ARROW
);
186 MAP_BUILTIN( PointerStyle::RefHand
, GDK_HAND2
);
187 MAP_BUILTIN( PointerStyle::Hand
, GDK_HAND2
);
188 MAP_BUILTIN( PointerStyle::Pen
, GDK_PENCIL
);
190 MAP_BUILTIN( PointerStyle::HSplit
, GDK_SB_H_DOUBLE_ARROW
);
191 MAP_BUILTIN( PointerStyle::VSplit
, GDK_SB_V_DOUBLE_ARROW
);
193 MAP_BUILTIN( PointerStyle::Move
, GDK_FLEUR
);
195 MAKE_CURSOR( PointerStyle::Null
, null
, RID_CURSOR_NULL
);
196 MAKE_CURSOR( PointerStyle::Magnify
, magnify_
, RID_CURSOR_MAGNIFY
);
197 MAKE_CURSOR( PointerStyle::Fill
, fill_
, RID_CURSOR_FILL
);
198 MAKE_CURSOR( PointerStyle::MoveData
, movedata_
, RID_CURSOR_MOVE_DATA
);
199 MAKE_CURSOR( PointerStyle::CopyData
, copydata_
, RID_CURSOR_COPY_DATA
);
200 MAKE_CURSOR( PointerStyle::MoveFile
, movefile_
, RID_CURSOR_MOVE_FILE
);
201 MAKE_CURSOR( PointerStyle::CopyFile
, copyfile_
, RID_CURSOR_COPY_FILE
);
202 MAKE_CURSOR( PointerStyle::MoveFiles
, movefiles_
, RID_CURSOR_MOVE_FILES
);
203 MAKE_CURSOR( PointerStyle::CopyFiles
, copyfiles_
, RID_CURSOR_COPY_FILES
);
204 MAKE_CURSOR( PointerStyle::NotAllowed
, nodrop_
, RID_CURSOR_NOT_ALLOWED
);
205 MAKE_CURSOR( PointerStyle::Rotate
, rotate_
, RID_CURSOR_ROTATE
);
206 MAKE_CURSOR( PointerStyle::HShear
, hshear_
, RID_CURSOR_H_SHEAR
);
207 MAKE_CURSOR( PointerStyle::VShear
, vshear_
, RID_CURSOR_V_SHEAR
);
208 MAKE_CURSOR( PointerStyle::DrawLine
, drawline_
, RID_CURSOR_DRAW_LINE
);
209 MAKE_CURSOR( PointerStyle::DrawRect
, drawrect_
, RID_CURSOR_DRAW_RECT
);
210 MAKE_CURSOR( PointerStyle::DrawPolygon
, drawpolygon_
, RID_CURSOR_DRAW_POLYGON
);
211 MAKE_CURSOR( PointerStyle::DrawBezier
, drawbezier_
, RID_CURSOR_DRAW_BEZIER
);
212 MAKE_CURSOR( PointerStyle::DrawArc
, drawarc_
, RID_CURSOR_DRAW_ARC
);
213 MAKE_CURSOR( PointerStyle::DrawPie
, drawpie_
, RID_CURSOR_DRAW_PIE
);
214 MAKE_CURSOR( PointerStyle::DrawCircleCut
, drawcirclecut_
, RID_CURSOR_DRAW_CIRCLE_CUT
);
215 MAKE_CURSOR( PointerStyle::DrawEllipse
, drawellipse_
, RID_CURSOR_DRAW_ELLIPSE
);
216 MAKE_CURSOR( PointerStyle::DrawConnect
, drawconnect_
, RID_CURSOR_DRAW_CONNECT
);
217 MAKE_CURSOR( PointerStyle::DrawText
, drawtext_
, RID_CURSOR_DRAW_TEXT
);
218 MAKE_CURSOR( PointerStyle::Mirror
, mirror_
, RID_CURSOR_MIRROR
);
219 MAKE_CURSOR( PointerStyle::Crook
, crook_
, RID_CURSOR_CROOK
);
220 MAKE_CURSOR( PointerStyle::Crop
, crop_
, RID_CURSOR_CROP
);
221 MAKE_CURSOR( PointerStyle::MovePoint
, movepoint_
, RID_CURSOR_MOVE_POINT
);
222 MAKE_CURSOR( PointerStyle::MoveBezierWeight
, movebezierweight_
, RID_CURSOR_MOVE_BEZIER_WEIGHT
);
223 MAKE_CURSOR( PointerStyle::DrawFreehand
, drawfreehand_
, RID_CURSOR_DRAW_FREEHAND
);
224 MAKE_CURSOR( PointerStyle::DrawCaption
, drawcaption_
, RID_CURSOR_DRAW_CAPTION
);
225 MAKE_CURSOR( PointerStyle::LinkData
, linkdata_
, RID_CURSOR_LINK_DATA
);
226 MAKE_CURSOR( PointerStyle::MoveDataLink
, movedlnk_
, RID_CURSOR_MOVE_DATA_LINK
);
227 MAKE_CURSOR( PointerStyle::CopyDataLink
, copydlnk_
, RID_CURSOR_COPY_DATA_LINK
);
228 MAKE_CURSOR( PointerStyle::LinkFile
, linkfile_
, RID_CURSOR_LINK_FILE
);
229 MAKE_CURSOR( PointerStyle::MoveFileLink
, moveflnk_
, RID_CURSOR_MOVE_FILE_LINK
);
230 MAKE_CURSOR( PointerStyle::CopyFileLink
, copyflnk_
, RID_CURSOR_COPY_FILE_LINK
);
231 MAKE_CURSOR( PointerStyle::Chart
, chart_
, RID_CURSOR_CHART
);
232 MAKE_CURSOR( PointerStyle::Detective
, detective_
, RID_CURSOR_DETECTIVE
);
233 MAKE_CURSOR( PointerStyle::PivotCol
, pivotcol_
, RID_CURSOR_PIVOT_COLUMN
);
234 MAKE_CURSOR( PointerStyle::PivotRow
, pivotrow_
, RID_CURSOR_PIVOT_ROW
);
235 MAKE_CURSOR( PointerStyle::PivotField
, pivotfld_
, RID_CURSOR_PIVOT_FIELD
);
236 MAKE_CURSOR( PointerStyle::PivotDelete
, pivotdel_
, RID_CURSOR_PIVOT_DELETE
);
237 MAKE_CURSOR( PointerStyle::Chain
, chain_
, RID_CURSOR_CHAIN
);
238 MAKE_CURSOR( PointerStyle::ChainNotAllowed
, chainnot_
, RID_CURSOR_CHAIN_NOT_ALLOWED
);
239 MAKE_CURSOR( PointerStyle::AutoScrollN
, asn_
, RID_CURSOR_AUTOSCROLL_N
);
240 MAKE_CURSOR( PointerStyle::AutoScrollS
, ass_
, RID_CURSOR_AUTOSCROLL_S
);
241 MAKE_CURSOR( PointerStyle::AutoScrollW
, asw_
, RID_CURSOR_AUTOSCROLL_W
);
242 MAKE_CURSOR( PointerStyle::AutoScrollE
, ase_
, RID_CURSOR_AUTOSCROLL_E
);
243 MAKE_CURSOR( PointerStyle::AutoScrollNW
, asnw_
, RID_CURSOR_AUTOSCROLL_NW
);
244 MAKE_CURSOR( PointerStyle::AutoScrollNE
, asne_
, RID_CURSOR_AUTOSCROLL_NE
);
245 MAKE_CURSOR( PointerStyle::AutoScrollSW
, assw_
, RID_CURSOR_AUTOSCROLL_SW
);
246 MAKE_CURSOR( PointerStyle::AutoScrollSE
, asse_
, RID_CURSOR_AUTOSCROLL_SE
);
247 MAKE_CURSOR( PointerStyle::AutoScrollNS
, asns_
, RID_CURSOR_AUTOSCROLL_NS
);
248 MAKE_CURSOR( PointerStyle::AutoScrollWE
, aswe_
, RID_CURSOR_AUTOSCROLL_WE
);
249 MAKE_CURSOR( PointerStyle::AutoScrollNSWE
, asnswe_
, RID_CURSOR_AUTOSCROLL_NSWE
);
250 MAKE_CURSOR( PointerStyle::TextVertical
, vertcurs_
, RID_CURSOR_TEXT_VERTICAL
);
253 MAKE_CURSOR( PointerStyle::TabSelectS
, tblsels_
, RID_CURSOR_TAB_SELECT_S
);
254 MAKE_CURSOR( PointerStyle::TabSelectE
, tblsele_
, RID_CURSOR_TAB_SELECT_E
);
255 MAKE_CURSOR( PointerStyle::TabSelectSE
, tblselse_
, RID_CURSOR_TAB_SELECT_SE
);
256 MAKE_CURSOR( PointerStyle::TabSelectW
, tblselw_
, RID_CURSOR_TAB_SELECT_W
);
257 MAKE_CURSOR( PointerStyle::TabSelectSW
, tblselsw_
, RID_CURSOR_TAB_SELECT_SW
);
259 MAKE_CURSOR( PointerStyle::HideWhitespace
, hidewhitespace_
, RID_CURSOR_HIDE_WHITESPACE
);
260 MAKE_CURSOR( PointerStyle::ShowWhitespace
, showwhitespace_
, RID_CURSOR_SHOW_WHITESPACE
);
263 SAL_WARN( "vcl.gtk", "pointer " << static_cast<int>(ePointerStyle
) << "not implemented" );
267 pCursor
= gdk_cursor_new_for_display( m_pGdkDisplay
, GDK_LEFT_PTR
);
269 m_aCursors
[ ePointerStyle
] = pCursor
;
272 return m_aCursors
[ ePointerStyle
];
275 int GtkSalDisplay::CaptureMouse( SalFrame
* pSFrame
)
277 GtkSalFrame
* pFrame
= static_cast<GtkSalFrame
*>(pSFrame
);
282 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( FALSE
);
283 m_pCapture
= nullptr;
289 if( pFrame
== m_pCapture
)
291 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( FALSE
);
295 pFrame
->grabPointer( TRUE
);
299 /**********************************************************************
301 **********************************************************************/
303 GtkSalData::GtkSalData( SalInstance
*pInstance
)
304 : GenericUnixSalData( SAL_DATA_GTK3
, pInstance
)
306 , m_aDispatchCondition()
307 , m_pDocumentFocusListener(nullptr)
309 m_pUserEvent
= nullptr;
312 #if defined(GDK_WINDOWING_X11)
313 static XIOErrorHandler aOrigXIOErrorHandler
= nullptr;
317 static int XIOErrorHdl(Display
*)
319 fprintf(stderr
, "X IO Error\n");
321 // avoid crashes in unrelated threads that still run while atexit
322 // handlers are in progress
328 GtkSalData::~GtkSalData()
331 g_warning ("TESTME: We used to have a stop-timer here, but the central code should do this");
333 // sanity check: at this point nobody should be yielding, but wake them
334 // up anyway before the condition they're waiting on gets destroyed.
335 m_aDispatchCondition
.set();
337 osl::MutexGuard
g( m_aDispatchMutex
);
340 g_source_destroy (m_pUserEvent
);
341 g_source_unref (m_pUserEvent
);
342 m_pUserEvent
= nullptr;
344 #if defined(GDK_WINDOWING_X11)
345 if (DLSYM_GDK_IS_X11_DISPLAY(gdk_display_get_default()))
346 XSetIOErrorHandler(aOrigXIOErrorHandler
);
350 void GtkSalData::Dispose()
355 /// Allows events to be processed, returns true if we processed an event.
356 bool GtkSalData::Yield( bool bWait
, bool bHandleAllCurrentEvents
)
358 /* #i33212# only enter g_main_context_iteration in one thread at any one
359 * time, else one of them potentially will never end as long as there is
360 * another thread in there. Having only one yielding thread actually dispatch
361 * fits the vcl event model (see e.g. the generic plugin).
363 bool bDispatchThread
= false;
364 bool bWasEvent
= false;
366 // release YieldMutex (and re-acquire at block end)
367 SolarMutexReleaser aReleaser
;
368 if( m_aDispatchMutex
.tryToAcquire() )
369 bDispatchThread
= true;
372 return false; // someone else is waiting already, return
375 if( bDispatchThread
)
377 int nMaxEvents
= bHandleAllCurrentEvents
? 100 : 1;
378 bool wasOneEvent
= TRUE
;
379 while( nMaxEvents
-- && wasOneEvent
)
381 wasOneEvent
= g_main_context_iteration( nullptr, bWait
&& !bWasEvent
);
386 std::rethrow_exception(m_aException
);
390 /* #i41693# in case the dispatch thread hangs in join
391 * for this thread the condition will never be set
392 * workaround: timeout of 1 second an emergency exit
394 // we are the dispatch thread
395 m_aDispatchCondition
.reset();
396 m_aDispatchCondition
.wait(std::chrono::seconds(1));
400 if( bDispatchThread
)
402 m_aDispatchMutex
.release();
404 m_aDispatchCondition
.set(); // trigger non dispatch thread yields
410 void GtkSalData::Init()
412 SAL_INFO( "vcl.gtk", "GtkMainloop::Init()" );
415 * open connection to X11 Display
417 * o -display command line parameter,
418 * o $DISPLAY environment variable
422 GdkDisplay
*pGdkDisp
= nullptr;
424 // is there a -display command line parameter?
425 rtl_TextEncoding aEnc
= osl_getThreadTextEncoding();
426 int nParams
= osl_getCommandArgCount();
428 OUString aParam
, aBin
;
429 char** pCmdLineAry
= new char*[ nParams
+1 ];
430 osl_getExecutableFile( &aParam
.pData
);
431 osl_getSystemPathFromFileURL( aParam
.pData
, &aBin
.pData
);
432 pCmdLineAry
[0] = g_strdup( OUStringToOString( aBin
, aEnc
).getStr() );
433 for (int i
= 0; i
< nParams
; ++i
)
435 osl_getCommandArg(i
, &aParam
.pData
);
436 OString
aBParam( OUStringToOString( aParam
, aEnc
) );
438 if( aParam
== "-display" || aParam
== "--display" )
440 pCmdLineAry
[i
+1] = g_strdup( "--display" );
441 osl_getCommandArg(i
+1, &aParam
.pData
);
442 aDisplay
= OUStringToOString( aParam
, aEnc
);
445 pCmdLineAry
[i
+1] = g_strdup( aBParam
.getStr() );
450 g_set_application_name(SalGenericSystem::getFrameClassName());
452 // Set consistent name of the root accessible
453 OUString aAppName
= Application::GetAppName();
454 if( !aAppName
.isEmpty() )
456 OString aPrgName
= OUStringToOString(aAppName
, aEnc
);
457 g_set_prgname(aPrgName
.getStr());
461 gtk_init_check( &nParams
, &pCmdLineAry
);
462 gdk_error_trap_push();
464 for (int i
= 0; i
< nParams
; ++i
)
465 g_free( pCmdLineAry
[i
] );
466 delete [] pCmdLineAry
;
468 #if OSL_DEBUG_LEVEL > 1
469 if (g_getenv("SAL_DEBUG_UPDATES"))
470 gdk_window_set_debug_updates (TRUE
);
473 pGdkDisp
= gdk_display_get_default();
476 OUString aProgramFileURL
;
477 osl_getExecutableFile( &aProgramFileURL
.pData
);
478 OUString aProgramSystemPath
;
479 osl_getSystemPathFromFileURL (aProgramFileURL
.pData
, &aProgramSystemPath
.pData
);
480 OString aProgramName
= OUStringToOString(
482 osl_getThreadTextEncoding() );
483 fprintf( stderr
, "%s X11 error: Can't open display: %s\n",
484 aProgramName
.getStr(), aDisplay
.getStr());
485 fprintf( stderr
, " Set DISPLAY environment variable, use -display option\n");
486 fprintf( stderr
, " or check permissions of your X-Server\n");
487 fprintf( stderr
, " (See \"man X\" resp. \"man xhost\" for details)\n");
492 #if defined(GDK_WINDOWING_X11)
493 if (DLSYM_GDK_IS_X11_DISPLAY(pGdkDisp
))
494 aOrigXIOErrorHandler
= XSetIOErrorHandler(XIOErrorHdl
);
497 GtkSalDisplay
*pDisplay
= new GtkSalDisplay( pGdkDisp
);
498 SetDisplay( pDisplay
);
500 //FIXME: unwind keyboard extension bits
502 // add signal handler to notify screen size changes
503 int nScreens
= gdk_display_get_n_screens( pGdkDisp
);
504 for( int n
= 0; n
< nScreens
; n
++ )
506 GdkScreen
*pScreen
= gdk_display_get_screen( pGdkDisp
, n
);
509 pDisplay
->screenSizeChanged( pScreen
);
510 pDisplay
->monitorsChanged( pScreen
);
511 g_signal_connect( G_OBJECT(pScreen
), "size-changed",
512 G_CALLBACK(signalScreenSizeChanged
), pDisplay
);
513 g_signal_connect( G_OBJECT(pScreen
), "monitors-changed",
514 G_CALLBACK(signalMonitorsChanged
), GetGtkDisplay() );
519 void GtkSalData::ErrorTrapPush()
521 gdk_error_trap_push ();
524 bool GtkSalData::ErrorTrapPop( bool bIgnoreError
)
528 gdk_error_trap_pop_ignored (); // faster
531 return gdk_error_trap_pop () != 0;
534 #if !GLIB_CHECK_VERSION(2,32,0)
535 #define G_SOURCE_REMOVE FALSE
540 struct SalGtkTimeoutSource
{
543 GtkSalTimer
*pInstance
;
546 static void sal_gtk_timeout_defer( SalGtkTimeoutSource
*pTSource
)
548 g_get_current_time( &pTSource
->aFireTime
);
549 g_time_val_add( &pTSource
->aFireTime
, pTSource
->pInstance
->m_nTimeoutMS
* 1000 );
552 static gboolean
sal_gtk_timeout_expired( SalGtkTimeoutSource
*pTSource
,
553 gint
*nTimeoutMS
, GTimeVal
const *pTimeNow
)
555 glong nDeltaSec
= pTSource
->aFireTime
.tv_sec
- pTimeNow
->tv_sec
;
556 glong nDeltaUSec
= pTSource
->aFireTime
.tv_usec
- pTimeNow
->tv_usec
;
557 if( nDeltaSec
< 0 || ( nDeltaSec
== 0 && nDeltaUSec
< 0) )
564 nDeltaUSec
+= 1000000;
567 // if the clock changes backwards we need to cope ...
568 if( static_cast<unsigned long>(nDeltaSec
) > 1 + ( pTSource
->pInstance
->m_nTimeoutMS
/ 1000 ) )
570 sal_gtk_timeout_defer( pTSource
);
574 *nTimeoutMS
= MIN( G_MAXINT
, ( nDeltaSec
* 1000 + (nDeltaUSec
+ 999) / 1000 ) );
576 return *nTimeoutMS
== 0;
579 static gboolean
sal_gtk_timeout_prepare( GSource
*pSource
, gint
*nTimeoutMS
)
581 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
584 g_get_current_time( &aTimeNow
);
586 return sal_gtk_timeout_expired( pTSource
, nTimeoutMS
, &aTimeNow
);
589 static gboolean
sal_gtk_timeout_check( GSource
*pSource
)
591 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
594 g_get_current_time( &aTimeNow
);
596 return ( pTSource
->aFireTime
.tv_sec
< aTimeNow
.tv_sec
||
597 ( pTSource
->aFireTime
.tv_sec
== aTimeNow
.tv_sec
&&
598 pTSource
->aFireTime
.tv_usec
< aTimeNow
.tv_usec
) );
601 static gboolean
sal_gtk_timeout_dispatch( GSource
*pSource
, GSourceFunc
, gpointer
)
603 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
605 if( !pTSource
->pInstance
)
608 SolarMutexGuard aGuard
;
610 sal_gtk_timeout_defer( pTSource
);
612 ImplSVData
* pSVData
= ImplGetSVData();
613 if( pSVData
->maSchedCtx
.mpSalTimer
)
614 pSVData
->maSchedCtx
.mpSalTimer
->CallCallback();
616 return G_SOURCE_REMOVE
;
619 static GSourceFuncs sal_gtk_timeout_funcs
=
621 sal_gtk_timeout_prepare
,
622 sal_gtk_timeout_check
,
623 sal_gtk_timeout_dispatch
,
624 nullptr, nullptr, nullptr
628 static SalGtkTimeoutSource
*
629 create_sal_gtk_timeout( GtkSalTimer
*pTimer
)
631 GSource
*pSource
= g_source_new( &sal_gtk_timeout_funcs
, sizeof( SalGtkTimeoutSource
) );
632 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
633 pTSource
->pInstance
= pTimer
;
635 // #i36226# timers should be executed with lower priority
636 // than XEvents like in generic plugin
637 g_source_set_priority( pSource
, G_PRIORITY_LOW
);
638 g_source_set_can_recurse( pSource
, TRUE
);
639 g_source_set_callback( pSource
,
640 /* unused dummy */ g_idle_remove_by_data
,
642 g_source_attach( pSource
, g_main_context_default() );
644 g_source_set_name( pSource
, "VCL timeout source" );
647 sal_gtk_timeout_defer( pTSource
);
652 GtkSalTimer::GtkSalTimer()
653 : m_pTimeout(nullptr)
658 GtkSalTimer::~GtkSalTimer()
660 GtkInstance
*pInstance
= static_cast<GtkInstance
*>(GetSalData()->m_pInstance
);
661 pInstance
->RemoveTimer();
665 bool GtkSalTimer::Expired()
667 if( !m_pTimeout
|| g_source_is_destroyed( &m_pTimeout
->aParent
) )
672 g_get_current_time( &aTimeNow
);
673 return !!sal_gtk_timeout_expired( m_pTimeout
, &nDummy
, &aTimeNow
);
676 void GtkSalTimer::Start( sal_uInt64 nMS
)
678 // glib is not 64bit safe in this regard.
679 assert( nMS
<= G_MAXINT
);
680 if ( nMS
> G_MAXINT
)
682 m_nTimeoutMS
= nMS
; // for restarting
683 Stop(); // FIXME: ideally re-use an existing m_pTimeout
684 m_pTimeout
= create_sal_gtk_timeout( this );
687 void GtkSalTimer::Stop()
691 g_source_destroy( &m_pTimeout
->aParent
);
692 g_source_unref( &m_pTimeout
->aParent
);
693 m_pTimeout
= nullptr;
698 static gboolean
call_userEventFn( void *data
)
700 SolarMutexGuard aGuard
;
701 const SalGenericDisplay
*pDisplay
= GetGenericUnixSalData()->GetDisplay();
704 GtkSalDisplay
*pThisDisplay
= static_cast<GtkSalData
*>(data
)->GetGtkDisplay();
705 assert(static_cast<const SalGenericDisplay
*>(pThisDisplay
) == pDisplay
);
706 pThisDisplay
->DispatchInternalEvent();
712 void GtkSalData::TriggerUserEventProcessing()
715 g_main_context_wakeup (nullptr); // really needed ?
716 else // nothing pending anyway
718 m_pUserEvent
= g_idle_source_new();
719 // tdf#110737 set user-events to a lower priority than system redraw
720 // events, which is G_PRIORITY_HIGH_IDLE + 20, so presentations
721 // queue-redraw has a chance to be fulfilled
722 g_source_set_priority (m_pUserEvent
, G_PRIORITY_HIGH_IDLE
+ 30);
723 g_source_set_can_recurse (m_pUserEvent
, TRUE
);
724 g_source_set_callback (m_pUserEvent
, call_userEventFn
,
725 static_cast<gpointer
>(this), nullptr);
726 g_source_attach (m_pUserEvent
, g_main_context_default ());
730 void GtkSalData::TriggerAllUserEventsProcessed()
732 assert( m_pUserEvent
);
733 g_source_destroy( m_pUserEvent
);
734 g_source_unref( m_pUserEvent
);
735 m_pUserEvent
= nullptr;
738 void GtkSalDisplay::TriggerUserEventProcessing()
740 GetGtkSalData()->TriggerUserEventProcessing();
743 void GtkSalDisplay::TriggerAllUserEventsProcessed()
745 GetGtkSalData()->TriggerAllUserEventsProcessed();
748 GtkWidget
* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow
) const
750 for (auto pSalFrame
: m_aFrames
)
752 const SystemEnvData
* pEnvData
= pSalFrame
->GetSystemData();
753 if (pEnvData
->aWindow
== hWindow
)
754 return GTK_WIDGET(pEnvData
->pWidget
);
759 void GtkSalDisplay::deregisterFrame( SalFrame
* pFrame
)
761 if( m_pCapture
== pFrame
)
763 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( FALSE
);
764 m_pCapture
= nullptr;
766 SalGenericDisplay::deregisterFrame( pFrame
);
769 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */