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 <o3tl/safeint.hxx>
35 #include <osl/thread.h>
36 #include <osl/process.h>
38 #include <vcl/svapp.hxx>
39 #include <sal/log.hxx>
45 using namespace vcl_sal
;
47 /***************************************************************
48 * class GtkSalDisplay *
49 ***************************************************************/
51 static GdkFilterReturn
call_filterGdkEvent( GdkXEvent
* sys_event
,
55 GtkSalDisplay
*pDisplay
= static_cast<GtkSalDisplay
*>(data
);
56 return pDisplay
->filterGdkEvent( sys_event
);
60 GtkSalDisplay::GtkSalDisplay( GdkDisplay
* pDisplay
) :
61 m_pSys( GtkSalSystem::GetSingleton() ),
62 m_pGdkDisplay( pDisplay
),
63 m_bStartupCompleted( false )
65 for(GdkCursor
* & rpCsr
: m_aCursors
)
68 // FIXME: unify this with SalInst's filter too ?
69 gdk_window_add_filter( nullptr, call_filterGdkEvent
, this );
71 if ( getenv( "SAL_IGNOREXERRORS" ) )
72 GetGenericUnixSalData()->ErrorTrapPush(); // and leak the trap
74 m_bX11Display
= DLSYM_GDK_IS_X11_DISPLAY( m_pGdkDisplay
);
76 gtk_widget_set_default_direction(AllSettings::GetLayoutRTL() ? GTK_TEXT_DIR_RTL
: GTK_TEXT_DIR_LTR
);
79 GtkSalDisplay::~GtkSalDisplay()
81 gdk_window_remove_filter( nullptr, call_filterGdkEvent
, this );
83 if( !m_bStartupCompleted
)
84 gdk_notify_startup_complete();
86 for(GdkCursor
* & rpCsr
: m_aCursors
)
88 gdk_cursor_unref( rpCsr
);
93 static void signalScreenSizeChanged( GdkScreen
* pScreen
, gpointer data
)
95 GtkSalDisplay
* pDisp
= static_cast<GtkSalDisplay
*>(data
);
96 pDisp
->screenSizeChanged( pScreen
);
99 static void signalMonitorsChanged( GdkScreen
* pScreen
, gpointer data
)
101 GtkSalDisplay
* pDisp
= static_cast<GtkSalDisplay
*>(data
);
102 pDisp
->monitorsChanged( pScreen
);
107 GdkFilterReturn
GtkSalDisplay::filterGdkEvent( GdkXEvent
* )
109 (void) this; // loplugin:staticmethods
110 //FIXME: implement filterGdkEvent ...
111 return GDK_FILTER_CONTINUE
;
114 void GtkSalDisplay::screenSizeChanged( GdkScreen
const * pScreen
)
116 m_pSys
->countScreenMonitors();
118 emitDisplayChanged();
121 void GtkSalDisplay::monitorsChanged( GdkScreen
const * pScreen
)
123 m_pSys
->countScreenMonitors();
125 emitDisplayChanged();
128 GdkCursor
* GtkSalDisplay::getFromSvg(OUString
const & name
, int nXHot
, int nYHot
)
130 GdkPixbuf
* pPixBuf
= load_icon_by_name(name
);
131 assert(pPixBuf
&& "missing image?");
135 guint nDefaultCursorSize
= gdk_display_get_default_cursor_size( m_pGdkDisplay
);
136 int nPixWidth
= gdk_pixbuf_get_width(pPixBuf
);
137 int nPixHeight
= gdk_pixbuf_get_height(pPixBuf
);
138 double fScalefactor
= static_cast<double>(nDefaultCursorSize
) / std::max(nPixWidth
, nPixHeight
);
139 GdkPixbuf
* pScaledPixBuf
= gdk_pixbuf_scale_simple(pPixBuf
,
140 nPixWidth
* fScalefactor
,
141 nPixHeight
* fScalefactor
,
143 g_object_unref(pPixBuf
);
144 GdkCursor
* pCursor
= gdk_cursor_new_from_pixbuf(m_pGdkDisplay
, pScaledPixBuf
,
145 nXHot
* fScalefactor
, nYHot
* fScalefactor
);
149 #define MAKE_CURSOR( vcl_name, name, name2 ) \
151 pCursor = getFromSvg(name2, name##curs_x_hot, name##curs_y_hot); \
153 #define MAP_BUILTIN( vcl_name, gdk_name ) \
155 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
158 GdkCursor
*GtkSalDisplay::getCursor( PointerStyle ePointerStyle
)
160 if ( !m_aCursors
[ ePointerStyle
] )
162 GdkCursor
*pCursor
= nullptr;
164 switch( ePointerStyle
)
166 MAP_BUILTIN( PointerStyle::Arrow
, GDK_LEFT_PTR
);
167 MAP_BUILTIN( PointerStyle::Text
, GDK_XTERM
);
168 MAP_BUILTIN( PointerStyle::Help
, GDK_QUESTION_ARROW
);
169 MAP_BUILTIN( PointerStyle::Cross
, GDK_CROSSHAIR
);
170 MAP_BUILTIN( PointerStyle::Wait
, GDK_WATCH
);
172 MAP_BUILTIN( PointerStyle::NSize
, GDK_SB_V_DOUBLE_ARROW
);
173 MAP_BUILTIN( PointerStyle::SSize
, GDK_SB_V_DOUBLE_ARROW
);
174 MAP_BUILTIN( PointerStyle::WSize
, GDK_SB_H_DOUBLE_ARROW
);
175 MAP_BUILTIN( PointerStyle::ESize
, GDK_SB_H_DOUBLE_ARROW
);
177 MAP_BUILTIN( PointerStyle::NWSize
, GDK_TOP_LEFT_CORNER
);
178 MAP_BUILTIN( PointerStyle::NESize
, GDK_TOP_RIGHT_CORNER
);
179 MAP_BUILTIN( PointerStyle::SWSize
, GDK_BOTTOM_LEFT_CORNER
);
180 MAP_BUILTIN( PointerStyle::SESize
, GDK_BOTTOM_RIGHT_CORNER
);
182 MAP_BUILTIN( PointerStyle::WindowNSize
, GDK_TOP_SIDE
);
183 MAP_BUILTIN( PointerStyle::WindowSSize
, GDK_BOTTOM_SIDE
);
184 MAP_BUILTIN( PointerStyle::WindowWSize
, GDK_LEFT_SIDE
);
185 MAP_BUILTIN( PointerStyle::WindowESize
, GDK_RIGHT_SIDE
);
187 MAP_BUILTIN( PointerStyle::WindowNWSize
, GDK_TOP_LEFT_CORNER
);
188 MAP_BUILTIN( PointerStyle::WindowNESize
, GDK_TOP_RIGHT_CORNER
);
189 MAP_BUILTIN( PointerStyle::WindowSWSize
, GDK_BOTTOM_LEFT_CORNER
);
190 MAP_BUILTIN( PointerStyle::WindowSESize
, GDK_BOTTOM_RIGHT_CORNER
);
192 MAP_BUILTIN( PointerStyle::HSizeBar
, GDK_SB_H_DOUBLE_ARROW
);
193 MAP_BUILTIN( PointerStyle::VSizeBar
, GDK_SB_V_DOUBLE_ARROW
);
195 MAP_BUILTIN( PointerStyle::RefHand
, GDK_HAND2
);
196 MAP_BUILTIN( PointerStyle::Hand
, GDK_HAND2
);
197 MAP_BUILTIN( PointerStyle::Pen
, GDK_PENCIL
);
199 MAP_BUILTIN( PointerStyle::HSplit
, GDK_SB_H_DOUBLE_ARROW
);
200 MAP_BUILTIN( PointerStyle::VSplit
, GDK_SB_V_DOUBLE_ARROW
);
202 MAP_BUILTIN( PointerStyle::Move
, GDK_FLEUR
);
204 MAKE_CURSOR( PointerStyle::Null
, null
, RID_CURSOR_NULL
);
205 MAKE_CURSOR( PointerStyle::Magnify
, magnify_
, RID_CURSOR_MAGNIFY
);
206 MAKE_CURSOR( PointerStyle::Fill
, fill_
, RID_CURSOR_FILL
);
207 MAKE_CURSOR( PointerStyle::MoveData
, movedata_
, RID_CURSOR_MOVE_DATA
);
208 MAKE_CURSOR( PointerStyle::CopyData
, copydata_
, RID_CURSOR_COPY_DATA
);
209 MAKE_CURSOR( PointerStyle::MoveFile
, movefile_
, RID_CURSOR_MOVE_FILE
);
210 MAKE_CURSOR( PointerStyle::CopyFile
, copyfile_
, RID_CURSOR_COPY_FILE
);
211 MAKE_CURSOR( PointerStyle::MoveFiles
, movefiles_
, RID_CURSOR_MOVE_FILES
);
212 MAKE_CURSOR( PointerStyle::CopyFiles
, copyfiles_
, RID_CURSOR_COPY_FILES
);
213 MAKE_CURSOR( PointerStyle::NotAllowed
, nodrop_
, RID_CURSOR_NOT_ALLOWED
);
214 MAKE_CURSOR( PointerStyle::Rotate
, rotate_
, RID_CURSOR_ROTATE
);
215 MAKE_CURSOR( PointerStyle::HShear
, hshear_
, RID_CURSOR_H_SHEAR
);
216 MAKE_CURSOR( PointerStyle::VShear
, vshear_
, RID_CURSOR_V_SHEAR
);
217 MAKE_CURSOR( PointerStyle::DrawLine
, drawline_
, RID_CURSOR_DRAW_LINE
);
218 MAKE_CURSOR( PointerStyle::DrawRect
, drawrect_
, RID_CURSOR_DRAW_RECT
);
219 MAKE_CURSOR( PointerStyle::DrawPolygon
, drawpolygon_
, RID_CURSOR_DRAW_POLYGON
);
220 MAKE_CURSOR( PointerStyle::DrawBezier
, drawbezier_
, RID_CURSOR_DRAW_BEZIER
);
221 MAKE_CURSOR( PointerStyle::DrawArc
, drawarc_
, RID_CURSOR_DRAW_ARC
);
222 MAKE_CURSOR( PointerStyle::DrawPie
, drawpie_
, RID_CURSOR_DRAW_PIE
);
223 MAKE_CURSOR( PointerStyle::DrawCircleCut
, drawcirclecut_
, RID_CURSOR_DRAW_CIRCLE_CUT
);
224 MAKE_CURSOR( PointerStyle::DrawEllipse
, drawellipse_
, RID_CURSOR_DRAW_ELLIPSE
);
225 MAKE_CURSOR( PointerStyle::DrawConnect
, drawconnect_
, RID_CURSOR_DRAW_CONNECT
);
226 MAKE_CURSOR( PointerStyle::DrawText
, drawtext_
, RID_CURSOR_DRAW_TEXT
);
227 MAKE_CURSOR( PointerStyle::Mirror
, mirror_
, RID_CURSOR_MIRROR
);
228 MAKE_CURSOR( PointerStyle::Crook
, crook_
, RID_CURSOR_CROOK
);
229 MAKE_CURSOR( PointerStyle::Crop
, crop_
, RID_CURSOR_CROP
);
230 MAKE_CURSOR( PointerStyle::MovePoint
, movepoint_
, RID_CURSOR_MOVE_POINT
);
231 MAKE_CURSOR( PointerStyle::MoveBezierWeight
, movebezierweight_
, RID_CURSOR_MOVE_BEZIER_WEIGHT
);
232 MAKE_CURSOR( PointerStyle::DrawFreehand
, drawfreehand_
, RID_CURSOR_DRAW_FREEHAND
);
233 MAKE_CURSOR( PointerStyle::DrawCaption
, drawcaption_
, RID_CURSOR_DRAW_CAPTION
);
234 MAKE_CURSOR( PointerStyle::LinkData
, linkdata_
, RID_CURSOR_LINK_DATA
);
235 MAKE_CURSOR( PointerStyle::MoveDataLink
, movedlnk_
, RID_CURSOR_MOVE_DATA_LINK
);
236 MAKE_CURSOR( PointerStyle::CopyDataLink
, copydlnk_
, RID_CURSOR_COPY_DATA_LINK
);
237 MAKE_CURSOR( PointerStyle::LinkFile
, linkfile_
, RID_CURSOR_LINK_FILE
);
238 MAKE_CURSOR( PointerStyle::MoveFileLink
, moveflnk_
, RID_CURSOR_MOVE_FILE_LINK
);
239 MAKE_CURSOR( PointerStyle::CopyFileLink
, copyflnk_
, RID_CURSOR_COPY_FILE_LINK
);
240 MAKE_CURSOR( PointerStyle::Chart
, chart_
, RID_CURSOR_CHART
);
241 MAKE_CURSOR( PointerStyle::Detective
, detective_
, RID_CURSOR_DETECTIVE
);
242 MAKE_CURSOR( PointerStyle::PivotCol
, pivotcol_
, RID_CURSOR_PIVOT_COLUMN
);
243 MAKE_CURSOR( PointerStyle::PivotRow
, pivotrow_
, RID_CURSOR_PIVOT_ROW
);
244 MAKE_CURSOR( PointerStyle::PivotField
, pivotfld_
, RID_CURSOR_PIVOT_FIELD
);
245 MAKE_CURSOR( PointerStyle::PivotDelete
, pivotdel_
, RID_CURSOR_PIVOT_DELETE
);
246 MAKE_CURSOR( PointerStyle::Chain
, chain_
, RID_CURSOR_CHAIN
);
247 MAKE_CURSOR( PointerStyle::ChainNotAllowed
, chainnot_
, RID_CURSOR_CHAIN_NOT_ALLOWED
);
248 MAKE_CURSOR( PointerStyle::AutoScrollN
, asn_
, RID_CURSOR_AUTOSCROLL_N
);
249 MAKE_CURSOR( PointerStyle::AutoScrollS
, ass_
, RID_CURSOR_AUTOSCROLL_S
);
250 MAKE_CURSOR( PointerStyle::AutoScrollW
, asw_
, RID_CURSOR_AUTOSCROLL_W
);
251 MAKE_CURSOR( PointerStyle::AutoScrollE
, ase_
, RID_CURSOR_AUTOSCROLL_E
);
252 MAKE_CURSOR( PointerStyle::AutoScrollNW
, asnw_
, RID_CURSOR_AUTOSCROLL_NW
);
253 MAKE_CURSOR( PointerStyle::AutoScrollNE
, asne_
, RID_CURSOR_AUTOSCROLL_NE
);
254 MAKE_CURSOR( PointerStyle::AutoScrollSW
, assw_
, RID_CURSOR_AUTOSCROLL_SW
);
255 MAKE_CURSOR( PointerStyle::AutoScrollSE
, asse_
, RID_CURSOR_AUTOSCROLL_SE
);
256 MAKE_CURSOR( PointerStyle::AutoScrollNS
, asns_
, RID_CURSOR_AUTOSCROLL_NS
);
257 MAKE_CURSOR( PointerStyle::AutoScrollWE
, aswe_
, RID_CURSOR_AUTOSCROLL_WE
);
258 MAKE_CURSOR( PointerStyle::AutoScrollNSWE
, asnswe_
, RID_CURSOR_AUTOSCROLL_NSWE
);
259 MAKE_CURSOR( PointerStyle::TextVertical
, vertcurs_
, RID_CURSOR_TEXT_VERTICAL
);
262 MAKE_CURSOR( PointerStyle::TabSelectS
, tblsels_
, RID_CURSOR_TAB_SELECT_S
);
263 MAKE_CURSOR( PointerStyle::TabSelectE
, tblsele_
, RID_CURSOR_TAB_SELECT_E
);
264 MAKE_CURSOR( PointerStyle::TabSelectSE
, tblselse_
, RID_CURSOR_TAB_SELECT_SE
);
265 MAKE_CURSOR( PointerStyle::TabSelectW
, tblselw_
, RID_CURSOR_TAB_SELECT_W
);
266 MAKE_CURSOR( PointerStyle::TabSelectSW
, tblselsw_
, RID_CURSOR_TAB_SELECT_SW
);
268 MAKE_CURSOR( PointerStyle::HideWhitespace
, hidewhitespace_
, RID_CURSOR_HIDE_WHITESPACE
);
269 MAKE_CURSOR( PointerStyle::ShowWhitespace
, showwhitespace_
, RID_CURSOR_SHOW_WHITESPACE
);
272 SAL_WARN( "vcl.gtk", "pointer " << static_cast<int>(ePointerStyle
) << "not implemented" );
276 pCursor
= gdk_cursor_new_for_display( m_pGdkDisplay
, GDK_LEFT_PTR
);
278 m_aCursors
[ ePointerStyle
] = pCursor
;
281 return m_aCursors
[ ePointerStyle
];
284 int GtkSalDisplay::CaptureMouse( SalFrame
* pSFrame
)
286 GtkSalFrame
* pFrame
= static_cast<GtkSalFrame
*>(pSFrame
);
291 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( false, false, false );
292 m_pCapture
= nullptr;
298 if( pFrame
== m_pCapture
)
300 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( false, false, false );
304 pFrame
->grabPointer( true, false, false );
308 /**********************************************************************
310 **********************************************************************/
312 GtkSalData::GtkSalData( SalInstance
*pInstance
)
313 : GenericUnixSalData( SAL_DATA_GTK3
, pInstance
)
315 , m_aDispatchCondition()
316 , m_pDocumentFocusListener(nullptr)
318 m_pUserEvent
= nullptr;
321 #if defined(GDK_WINDOWING_X11)
322 static XIOErrorHandler aOrigXIOErrorHandler
= nullptr;
326 static int XIOErrorHdl(Display
*)
328 fprintf(stderr
, "X IO Error\n");
330 // avoid crashes in unrelated threads that still run while atexit
331 // handlers are in progress
337 GtkSalData::~GtkSalData()
340 g_warning ("TESTME: We used to have a stop-timer here, but the central code should do this");
342 // sanity check: at this point nobody should be yielding, but wake them
343 // up anyway before the condition they're waiting on gets destroyed.
344 m_aDispatchCondition
.set();
346 osl::MutexGuard
g( m_aDispatchMutex
);
349 g_source_destroy (m_pUserEvent
);
350 g_source_unref (m_pUserEvent
);
351 m_pUserEvent
= nullptr;
353 #if defined(GDK_WINDOWING_X11)
354 if (DLSYM_GDK_IS_X11_DISPLAY(gdk_display_get_default()))
355 XSetIOErrorHandler(aOrigXIOErrorHandler
);
359 void GtkSalData::Dispose()
364 /// Allows events to be processed, returns true if we processed an event.
365 bool GtkSalData::Yield( bool bWait
, bool bHandleAllCurrentEvents
)
367 /* #i33212# only enter g_main_context_iteration in one thread at any one
368 * time, else one of them potentially will never end as long as there is
369 * another thread in there. Having only one yielding thread actually dispatch
370 * fits the vcl event model (see e.g. the generic plugin).
372 bool bDispatchThread
= false;
373 bool bWasEvent
= false;
375 // release YieldMutex (and re-acquire at block end)
376 SolarMutexReleaser aReleaser
;
377 if( m_aDispatchMutex
.tryToAcquire() )
378 bDispatchThread
= true;
381 return false; // someone else is waiting already, return
384 if( bDispatchThread
)
386 int nMaxEvents
= bHandleAllCurrentEvents
? 100 : 1;
387 bool wasOneEvent
= true;
388 while( nMaxEvents
-- && wasOneEvent
)
390 wasOneEvent
= g_main_context_iteration( nullptr, bWait
&& !bWasEvent
);
395 std::rethrow_exception(m_aException
);
399 /* #i41693# in case the dispatch thread hangs in join
400 * for this thread the condition will never be set
401 * workaround: timeout of 1 second an emergency exit
403 // we are the dispatch thread
404 m_aDispatchCondition
.reset();
405 m_aDispatchCondition
.wait(std::chrono::seconds(1));
409 if( bDispatchThread
)
411 m_aDispatchMutex
.release();
413 m_aDispatchCondition
.set(); // trigger non dispatch thread yields
419 void GtkSalData::Init()
421 SAL_INFO( "vcl.gtk", "GtkMainloop::Init()" );
424 * open connection to X11 Display
426 * o -display command line parameter,
427 * o $DISPLAY environment variable
431 GdkDisplay
*pGdkDisp
= nullptr;
433 // is there a -display command line parameter?
434 rtl_TextEncoding aEnc
= osl_getThreadTextEncoding();
435 int nParams
= osl_getCommandArgCount();
437 OUString aParam
, aBin
;
438 char** pCmdLineAry
= new char*[ nParams
+1 ];
439 osl_getExecutableFile( &aParam
.pData
);
440 osl_getSystemPathFromFileURL( aParam
.pData
, &aBin
.pData
);
441 pCmdLineAry
[0] = g_strdup( OUStringToOString( aBin
, aEnc
).getStr() );
442 for (int i
= 0; i
< nParams
; ++i
)
444 osl_getCommandArg(i
, &aParam
.pData
);
445 OString
aBParam( OUStringToOString( aParam
, aEnc
) );
447 if( aParam
== "-display" || aParam
== "--display" )
449 pCmdLineAry
[i
+1] = g_strdup( "--display" );
450 osl_getCommandArg(i
+1, &aParam
.pData
);
451 aDisplay
= OUStringToOString( aParam
, aEnc
);
454 pCmdLineAry
[i
+1] = g_strdup( aBParam
.getStr() );
459 g_set_application_name(SalGenericSystem::getFrameClassName());
461 // Set consistent name of the root accessible
462 OUString aAppName
= Application::GetAppName();
463 if( !aAppName
.isEmpty() )
465 OString aPrgName
= OUStringToOString(aAppName
, aEnc
);
466 g_set_prgname(aPrgName
.getStr());
470 gtk_init_check( &nParams
, &pCmdLineAry
);
471 gdk_error_trap_push();
473 for (int i
= 0; i
< nParams
; ++i
)
474 g_free( pCmdLineAry
[i
] );
475 delete [] pCmdLineAry
;
477 #if OSL_DEBUG_LEVEL > 1
478 if (g_getenv("SAL_DEBUG_UPDATES"))
479 gdk_window_set_debug_updates (TRUE
);
482 pGdkDisp
= gdk_display_get_default();
485 OUString aProgramFileURL
;
486 osl_getExecutableFile( &aProgramFileURL
.pData
);
487 OUString aProgramSystemPath
;
488 osl_getSystemPathFromFileURL (aProgramFileURL
.pData
, &aProgramSystemPath
.pData
);
489 OString aProgramName
= OUStringToOString(
491 osl_getThreadTextEncoding() );
492 fprintf( stderr
, "%s X11 error: Can't open display: %s\n",
493 aProgramName
.getStr(), aDisplay
.getStr());
494 fprintf( stderr
, " Set DISPLAY environment variable, use -display option\n");
495 fprintf( stderr
, " or check permissions of your X-Server\n");
496 fprintf( stderr
, " (See \"man X\" resp. \"man xhost\" for details)\n");
501 #if defined(GDK_WINDOWING_X11)
502 if (DLSYM_GDK_IS_X11_DISPLAY(pGdkDisp
))
503 aOrigXIOErrorHandler
= XSetIOErrorHandler(XIOErrorHdl
);
506 GtkSalDisplay
*pDisplay
= new GtkSalDisplay( pGdkDisp
);
507 SetDisplay( pDisplay
);
509 int nScreens
= gdk_display_get_n_screens( pGdkDisp
);
510 for( int n
= 0; n
< nScreens
; n
++ )
512 GdkScreen
*pScreen
= gdk_display_get_screen( pGdkDisp
, n
);
516 pDisplay
->screenSizeChanged( pScreen
);
517 pDisplay
->monitorsChanged( pScreen
);
518 // add signal handler to notify screen size changes
519 g_signal_connect( G_OBJECT(pScreen
), "size-changed",
520 G_CALLBACK(signalScreenSizeChanged
), pDisplay
);
521 g_signal_connect( G_OBJECT(pScreen
), "monitors-changed",
522 G_CALLBACK(signalMonitorsChanged
), GetGtkDisplay() );
525 set a provider to allow certain widgets to have no padding
527 a) little close button in menubar to close back to start-center
528 b) and small buttons in view->data sources (button.small-button)
529 c) small toolbar button in infobars (toolbar.small-button button)
530 d) comboboxes in the data browser for tdf#137695 (box#combobox button.small-button,
531 which would instead be combobox button.small-button if we didn't replace GtkComboBox,
532 see GtkInstanceComboBox for an explanation for why we do that)
533 e) entry in the data browser for tdf#137695 (entry.small-button)
535 GtkCssProvider
* pSmallButtonProvider
= gtk_css_provider_new();
536 static const gchar data
[] =
537 "button.small-button, toolbar.small-button button, combobox.small-button *.combo, box#combobox.small-button *.combo, entry.small-button { "
544 gtk_css_provider_load_from_data(pSmallButtonProvider
, data
, -1, nullptr);
546 gtk_style_context_add_provider_for_screen(pScreen
, GTK_STYLE_PROVIDER(pSmallButtonProvider
),
547 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
551 void GtkSalData::ErrorTrapPush()
553 gdk_error_trap_push ();
556 bool GtkSalData::ErrorTrapPop( bool bIgnoreError
)
560 gdk_error_trap_pop_ignored (); // faster
563 return gdk_error_trap_pop () != 0;
566 #if !GLIB_CHECK_VERSION(2,32,0)
567 #define G_SOURCE_REMOVE FALSE
572 struct SalGtkTimeoutSource
{
575 GtkSalTimer
*pInstance
;
578 static void sal_gtk_timeout_defer( SalGtkTimeoutSource
*pTSource
)
580 g_get_current_time( &pTSource
->aFireTime
);
581 g_time_val_add( &pTSource
->aFireTime
, pTSource
->pInstance
->m_nTimeoutMS
* 1000 );
584 static gboolean
sal_gtk_timeout_expired( SalGtkTimeoutSource
*pTSource
,
585 gint
*nTimeoutMS
, GTimeVal
const *pTimeNow
)
587 glong nDeltaSec
= pTSource
->aFireTime
.tv_sec
- pTimeNow
->tv_sec
;
588 glong nDeltaUSec
= pTSource
->aFireTime
.tv_usec
- pTimeNow
->tv_usec
;
589 if( nDeltaSec
< 0 || ( nDeltaSec
== 0 && nDeltaUSec
< 0) )
596 nDeltaUSec
+= 1000000;
599 // if the clock changes backwards we need to cope ...
600 if( o3tl::make_unsigned(nDeltaSec
) > 1 + ( pTSource
->pInstance
->m_nTimeoutMS
/ 1000 ) )
602 sal_gtk_timeout_defer( pTSource
);
606 *nTimeoutMS
= MIN( G_MAXINT
, ( nDeltaSec
* 1000 + (nDeltaUSec
+ 999) / 1000 ) );
608 return *nTimeoutMS
== 0;
611 static gboolean
sal_gtk_timeout_prepare( GSource
*pSource
, gint
*nTimeoutMS
)
613 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
616 g_get_current_time( &aTimeNow
);
618 return sal_gtk_timeout_expired( pTSource
, nTimeoutMS
, &aTimeNow
);
621 static gboolean
sal_gtk_timeout_check( GSource
*pSource
)
623 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
626 g_get_current_time( &aTimeNow
);
628 return ( pTSource
->aFireTime
.tv_sec
< aTimeNow
.tv_sec
||
629 ( pTSource
->aFireTime
.tv_sec
== aTimeNow
.tv_sec
&&
630 pTSource
->aFireTime
.tv_usec
< aTimeNow
.tv_usec
) );
633 static gboolean
sal_gtk_timeout_dispatch( GSource
*pSource
, GSourceFunc
, gpointer
)
635 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
637 if( !pTSource
->pInstance
)
640 SolarMutexGuard aGuard
;
642 sal_gtk_timeout_defer( pTSource
);
644 ImplSVData
* pSVData
= ImplGetSVData();
645 if( pSVData
->maSchedCtx
.mpSalTimer
)
646 pSVData
->maSchedCtx
.mpSalTimer
->CallCallback();
648 return G_SOURCE_REMOVE
;
651 static GSourceFuncs sal_gtk_timeout_funcs
=
653 sal_gtk_timeout_prepare
,
654 sal_gtk_timeout_check
,
655 sal_gtk_timeout_dispatch
,
656 nullptr, nullptr, nullptr
660 static SalGtkTimeoutSource
*
661 create_sal_gtk_timeout( GtkSalTimer
*pTimer
)
663 GSource
*pSource
= g_source_new( &sal_gtk_timeout_funcs
, sizeof( SalGtkTimeoutSource
) );
664 SalGtkTimeoutSource
*pTSource
= reinterpret_cast<SalGtkTimeoutSource
*>(pSource
);
665 pTSource
->pInstance
= pTimer
;
667 // #i36226# timers should be executed with lower priority
668 // than XEvents like in generic plugin
669 g_source_set_priority( pSource
, G_PRIORITY_LOW
);
670 g_source_set_can_recurse( pSource
, true );
671 g_source_set_callback( pSource
,
672 /* unused dummy */ g_idle_remove_by_data
,
674 g_source_attach( pSource
, g_main_context_default() );
676 g_source_set_name( pSource
, "VCL timeout source" );
679 sal_gtk_timeout_defer( pTSource
);
684 GtkSalTimer::GtkSalTimer()
685 : m_pTimeout(nullptr)
690 GtkSalTimer::~GtkSalTimer()
692 GtkInstance
*pInstance
= static_cast<GtkInstance
*>(GetSalData()->m_pInstance
);
693 pInstance
->RemoveTimer();
697 bool GtkSalTimer::Expired()
699 if( !m_pTimeout
|| g_source_is_destroyed( &m_pTimeout
->aParent
) )
704 g_get_current_time( &aTimeNow
);
705 return !!sal_gtk_timeout_expired( m_pTimeout
, &nDummy
, &aTimeNow
);
708 void GtkSalTimer::Start( sal_uInt64 nMS
)
710 // glib is not 64bit safe in this regard.
711 assert( nMS
<= G_MAXINT
);
712 if ( nMS
> G_MAXINT
)
714 m_nTimeoutMS
= nMS
; // for restarting
715 Stop(); // FIXME: ideally re-use an existing m_pTimeout
716 m_pTimeout
= create_sal_gtk_timeout( this );
719 void GtkSalTimer::Stop()
723 g_source_destroy( &m_pTimeout
->aParent
);
724 g_source_unref( &m_pTimeout
->aParent
);
725 m_pTimeout
= nullptr;
730 static gboolean
call_userEventFn( void *data
)
732 SolarMutexGuard aGuard
;
733 const SalGenericDisplay
*pDisplay
= GetGenericUnixSalData()->GetDisplay();
736 GtkSalDisplay
*pThisDisplay
= static_cast<GtkSalData
*>(data
)->GetGtkDisplay();
737 assert(static_cast<const SalGenericDisplay
*>(pThisDisplay
) == pDisplay
);
738 pThisDisplay
->DispatchInternalEvent();
744 void GtkSalData::TriggerUserEventProcessing()
747 g_main_context_wakeup (nullptr); // really needed ?
748 else // nothing pending anyway
750 m_pUserEvent
= g_idle_source_new();
751 // tdf#110737 set user-events to a lower priority than system redraw
752 // events, which is G_PRIORITY_HIGH_IDLE + 20, so presentations
753 // queue-redraw has a chance to be fulfilled
754 g_source_set_priority (m_pUserEvent
, G_PRIORITY_HIGH_IDLE
+ 30);
755 g_source_set_can_recurse (m_pUserEvent
, true);
756 g_source_set_callback (m_pUserEvent
, call_userEventFn
,
757 static_cast<gpointer
>(this), nullptr);
758 g_source_attach (m_pUserEvent
, g_main_context_default ());
762 void GtkSalData::TriggerAllUserEventsProcessed()
764 assert( m_pUserEvent
);
765 g_source_destroy( m_pUserEvent
);
766 g_source_unref( m_pUserEvent
);
767 m_pUserEvent
= nullptr;
770 void GtkSalDisplay::TriggerUserEventProcessing()
772 GetGtkSalData()->TriggerUserEventProcessing();
775 void GtkSalDisplay::TriggerAllUserEventsProcessed()
777 GetGtkSalData()->TriggerAllUserEventsProcessed();
780 GtkWidget
* GtkSalDisplay::findGtkWidgetForNativeHandle(sal_uIntPtr hWindow
) const
782 for (auto pSalFrame
: m_aFrames
)
784 const SystemEnvData
* pEnvData
= pSalFrame
->GetSystemData();
785 if (pEnvData
->GetWindowHandle(pSalFrame
) == hWindow
)
786 return GTK_WIDGET(pEnvData
->pWidget
);
791 void GtkSalDisplay::deregisterFrame( SalFrame
* pFrame
)
793 if( m_pCapture
== pFrame
)
795 static_cast<GtkSalFrame
*>(m_pCapture
)->grabPointer( false, false, false );
796 m_pCapture
= nullptr;
798 SalGenericDisplay::deregisterFrame( pFrame
);
801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */