nss: upgrade to release 3.73
[LibreOffice.git] / vcl / unx / gtk3 / gtk3gtkdata.cxx
blob1e46fd69b8bcd24a208aff00be305d3c177f8c28
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #if defined(FREEBSD) || defined(NETBSD)
25 #include <sys/types.h>
26 #include <sys/time.h>
27 #endif
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>
41 #include <chrono>
45 using namespace vcl_sal;
47 /***************************************************************
48 * class GtkSalDisplay *
49 ***************************************************************/
50 extern "C" {
51 static GdkFilterReturn call_filterGdkEvent( GdkXEvent* sys_event,
52 GdkEvent* /*event*/,
53 gpointer data )
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)
66 rpCsr = nullptr;
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)
87 if( rpCsr )
88 gdk_cursor_unref( rpCsr );
91 extern "C" {
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();
117 if (pScreen)
118 emitDisplayChanged();
121 void GtkSalDisplay::monitorsChanged( GdkScreen const * pScreen )
123 m_pSys->countScreenMonitors();
124 if (pScreen)
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?");
132 if (!pPixBuf)
133 return nullptr;
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,
142 GDK_INTERP_HYPER);
143 g_object_unref(pPixBuf);
144 GdkCursor* pCursor = gdk_cursor_new_from_pixbuf(m_pGdkDisplay, pScaledPixBuf,
145 nXHot * fScalefactor, nYHot * fScalefactor);
146 return pCursor;
149 #define MAKE_CURSOR( vcl_name, name, name2 ) \
150 case vcl_name: \
151 pCursor = getFromSvg(name2, name##curs_x_hot, name##curs_y_hot); \
152 break
153 #define MAP_BUILTIN( vcl_name, gdk_name ) \
154 case vcl_name: \
155 pCursor = gdk_cursor_new_for_display( m_pGdkDisplay, gdk_name ); \
156 break
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 );
261 // #i32329#
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 );
271 default:
272 SAL_WARN( "vcl.gtk", "pointer " << static_cast<int>(ePointerStyle) << "not implemented" );
273 break;
275 if( !pCursor )
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);
288 if( !pFrame )
290 if( m_pCapture )
291 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( false, false, false );
292 m_pCapture = nullptr;
293 return 0;
296 if( m_pCapture )
298 if( pFrame == m_pCapture )
299 return 1;
300 static_cast<GtkSalFrame*>(m_pCapture)->grabPointer( false, false, false );
303 m_pCapture = pFrame;
304 pFrame->grabPointer( true, false, false );
305 return 1;
308 /**********************************************************************
309 * class GtkSalData *
310 **********************************************************************/
312 GtkSalData::GtkSalData( SalInstance *pInstance )
313 : GenericUnixSalData( SAL_DATA_GTK3, pInstance )
314 , m_aDispatchMutex()
315 , m_aDispatchCondition()
316 , m_pDocumentFocusListener(nullptr)
318 m_pUserEvent = nullptr;
321 #if defined(GDK_WINDOWING_X11)
322 static XIOErrorHandler aOrigXIOErrorHandler = nullptr;
324 extern "C" {
326 static int XIOErrorHdl(Display *)
328 fprintf(stderr, "X IO Error\n");
329 _exit(1);
330 // avoid crashes in unrelated threads that still run while atexit
331 // handlers are in progress
335 #endif
337 GtkSalData::~GtkSalData()
339 Yield( true, true );
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 );
347 if (m_pUserEvent)
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);
356 #endif
359 void GtkSalData::Dispose()
361 deInitNWF();
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;
379 else if( ! bWait )
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 );
391 if( wasOneEvent )
392 bWasEvent = true;
394 if (m_aException)
395 std::rethrow_exception(m_aException);
397 else if( bWait )
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();
412 if( bWasEvent )
413 m_aDispatchCondition.set(); // trigger non dispatch thread yields
416 return bWasEvent;
419 void GtkSalData::Init()
421 SAL_INFO( "vcl.gtk", "GtkMainloop::Init()" );
424 * open connection to X11 Display
425 * try in this order:
426 * o -display command line parameter,
427 * o $DISPLAY environment variable
428 * o default display
431 GdkDisplay *pGdkDisp = nullptr;
433 // is there a -display command line parameter?
434 rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
435 int nParams = osl_getCommandArgCount();
436 OString aDisplay;
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 );
453 else
454 pCmdLineAry[i+1] = g_strdup( aBParam.getStr() );
456 // add executable
457 nParams++;
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());
469 // init gtk/gdk
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);
480 #endif
482 pGdkDisp = gdk_display_get_default();
483 if ( !pGdkDisp )
485 OUString aProgramFileURL;
486 osl_getExecutableFile( &aProgramFileURL.pData );
487 OUString aProgramSystemPath;
488 osl_getSystemPathFromFileURL (aProgramFileURL.pData, &aProgramSystemPath.pData);
489 OString aProgramName = OUStringToOString(
490 aProgramSystemPath,
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");
497 fflush( stderr );
498 exit(0);
501 #if defined(GDK_WINDOWING_X11)
502 if (DLSYM_GDK_IS_X11_DISPLAY(pGdkDisp))
503 aOrigXIOErrorHandler = XSetIOErrorHandler(XIOErrorHdl);
504 #endif
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 );
513 if (!pScreen)
514 continue;
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 { "
538 "padding: 0;"
539 "margin-left: 0px;"
540 "margin-right: 0px;"
541 "min-height: 18px;"
542 "min-width: 18px;"
543 "}";
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 )
558 if (bIgnoreError)
560 gdk_error_trap_pop_ignored (); // faster
561 return false;
563 return gdk_error_trap_pop () != 0;
566 #if !GLIB_CHECK_VERSION(2,32,0)
567 #define G_SOURCE_REMOVE FALSE
568 #endif
570 extern "C" {
572 struct SalGtkTimeoutSource {
573 GSource aParent;
574 GTimeVal aFireTime;
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) )
591 *nTimeoutMS = 0;
592 return true;
594 if( nDeltaUSec < 0 )
596 nDeltaUSec += 1000000;
597 nDeltaSec -= 1;
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 );
603 return true;
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);
615 GTimeVal aTimeNow;
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);
625 GTimeVal aTimeNow;
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 )
638 return FALSE;
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,
673 nullptr, nullptr );
674 g_source_attach( pSource, g_main_context_default() );
675 #ifdef DBG_UTIL
676 g_source_set_name( pSource, "VCL timeout source" );
677 #endif
679 sal_gtk_timeout_defer( pTSource );
681 return pTSource;
684 GtkSalTimer::GtkSalTimer()
685 : m_pTimeout(nullptr)
686 , m_nTimeoutMS(0)
690 GtkSalTimer::~GtkSalTimer()
692 GtkInstance *pInstance = static_cast<GtkInstance *>(GetSalData()->m_pInstance);
693 pInstance->RemoveTimer();
694 Stop();
697 bool GtkSalTimer::Expired()
699 if( !m_pTimeout || g_source_is_destroyed( &m_pTimeout->aParent ) )
700 return false;
702 gint nDummy = 0;
703 GTimeVal aTimeNow;
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 )
713 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()
721 if( m_pTimeout )
723 g_source_destroy( &m_pTimeout->aParent );
724 g_source_unref( &m_pTimeout->aParent );
725 m_pTimeout = nullptr;
729 extern "C" {
730 static gboolean call_userEventFn( void *data )
732 SolarMutexGuard aGuard;
733 const SalGenericDisplay *pDisplay = GetGenericUnixSalData()->GetDisplay();
734 if ( pDisplay )
736 GtkSalDisplay *pThisDisplay = static_cast<GtkSalData *>(data)->GetGtkDisplay();
737 assert(static_cast<const SalGenericDisplay *>(pThisDisplay) == pDisplay);
738 pThisDisplay->DispatchInternalEvent();
740 return true;
744 void GtkSalData::TriggerUserEventProcessing()
746 if (m_pUserEvent)
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);
788 return nullptr;
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: */