1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: gtkinst.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <osl/module.h>
35 #include <plugins/gtk/gtkdata.hxx>
36 #include <plugins/gtk/gtkinst.hxx>
39 #include <plugins/gtk/gtkframe.hxx>
40 #include <plugins/gtk/gtkobject.hxx>
41 #include <plugins/gtk/atkbridge.hxx>
43 #include <rtl/strbuf.hxx>
45 #if OSL_DEBUG_LEVEL > 1
53 GtkHookedYieldMutex::GtkHookedYieldMutex()
58 * These methods always occur in pairs
59 * A ThreadsEnter is followed by a ThreadsLeave
60 * We need to queue up the recursive lock count
61 * for each pair, so we can accurately restore
64 void GtkHookedYieldMutex::ThreadsEnter()
67 if( !aYieldStack
.empty() )
68 { /* Previously called ThreadsLeave() */
69 ULONG nCount
= aYieldStack
.front();
70 aYieldStack
.pop_front();
76 void GtkHookedYieldMutex::ThreadsLeave()
78 aYieldStack
.push_front( mnCount
);
80 #if OSL_DEBUG_LEVEL > 1
82 mnThreadId
!= NAMESPACE_VOS(OThread
)::getCurrentIdentifier())
83 fprintf( stderr
, "\n\n--- A different thread owns the mutex ...---\n\n\n");
91 void GtkHookedYieldMutex::acquire()
93 SalYieldMutex::acquire();
96 void GtkHookedYieldMutex::release()
98 SalYieldMutex::release();
103 #define GET_YIELD_MUTEX() static_cast<GtkHookedYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
104 static void GdkThreadsEnter( void )
106 GtkHookedYieldMutex
*pYieldMutex
= GET_YIELD_MUTEX();
107 pYieldMutex
->ThreadsEnter();
109 static void GdkThreadsLeave( void )
111 GtkHookedYieldMutex
*pYieldMutex
= GET_YIELD_MUTEX();
112 pYieldMutex
->ThreadsLeave();
114 static bool hookLocks( oslModule pModule
)
116 typedef void (*GdkLockFn
) (GCallback enter_fn
, GCallback leave_fn
);
118 GdkLockFn gdk_threads_set_lock_functions
=
119 (GdkLockFn
) osl_getAsciiFunctionSymbol( pModule
, "gdk_threads_set_lock_functions" );
120 if ( !gdk_threads_set_lock_functions
)
122 #if OSL_DEBUG_LEVEL > 1
123 fprintf( stderr
, "Failed to hook gdk threads locks\n" );
128 gdk_threads_set_lock_functions (GdkThreadsEnter
, GdkThreadsLeave
);
129 #if OSL_DEBUG_LEVEL > 1
130 fprintf( stderr
, "Hooked gdk threads locks\n" );
135 VCL_DLLPUBLIC SalInstance
* create_SalInstance( oslModule pModule
)
137 /* #i92121# workaround deadlocks in the X11 implementation
139 static const char* pNoXInitThreads
= getenv( "SAL_NO_XINITTHREADS" );
141 from now on we know that an X connection will be
142 established, so protect X against itself
144 if( ! ( pNoXInitThreads
&& *pNoXInitThreads
) )
147 #if OSL_DEBUG_LEVEL > 1
148 int nFd
= open( "/home/pl93762/log.txt", O_CREAT
| O_TRUNC
| O_WRONLY
, 0755 );
149 dup2( nFd
, STDERR_FILENO
);
152 const gchar
* pVersion
= gtk_check_version( 2, 2, 0 );
155 #if OSL_DEBUG_LEVEL > 1
156 fprintf( stderr
, "gtk version conflict: %s\n", pVersion
);
161 GtkYieldMutex
*pYieldMutex
;
163 // init gdk thread protection
164 if ( !g_thread_supported() )
165 g_thread_init( NULL
);
167 if ( hookLocks( pModule
) )
168 pYieldMutex
= new GtkHookedYieldMutex();
170 pYieldMutex
= new GtkYieldMutex();
174 GtkInstance
* pInstance
= new GtkInstance( pYieldMutex
);
175 #if OSL_DEBUG_LEVEL > 1
176 fprintf( stderr
, "creating GtkSalInstance 0x%p\n", pInstance
);
179 // initialize SalData
180 GtkData
*pSalData
= new GtkData();
181 SetSalData( pSalData
);
182 pSalData
->m_pInstance
= pInstance
;
192 GtkInstance::~GtkInstance()
197 SalFrame
* GtkInstance::CreateFrame( SalFrame
* pParent
, ULONG nStyle
)
199 return new GtkSalFrame( pParent
, nStyle
);
202 SalFrame
* GtkInstance::CreateChildFrame( SystemParentData
* pParentData
, ULONG
)
204 SalFrame
* pFrame
= new GtkSalFrame( pParentData
);
209 SalObject
* GtkInstance::CreateObject( SalFrame
* pParent
, SystemWindowData
* pWindowData
, BOOL bShow
)
211 // there is no method to set a visual for a GtkWidget
212 // so we need the X11SalObject in that case
214 return X11SalObject::CreateObject( pParent
, pWindowData
, bShow
);
216 return new GtkSalObject( static_cast<GtkSalFrame
*>(pParent
), bShow
);
221 typedef void*(* getDefaultFnc
)();
222 typedef void(* addItemFnc
)(void *, const char *);
225 void GtkInstance::AddToRecentDocumentList(const rtl::OUString
& rFileUrl
, const rtl::OUString
& rMimeType
)
227 #if GTK_CHECK_VERSION(2,10,0)
228 GtkRecentManager
*manager
= gtk_recent_manager_get_default ();
229 gtk_recent_manager_add_item (manager
, rtl::OUStringToOString(rFileUrl
, RTL_TEXTENCODING_UTF8
).getStr());
232 static getDefaultFnc sym_gtk_recent_manager_get_default
=
233 (getDefaultFnc
)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin
, "gtk_recent_manager_get_default" );
235 static addItemFnc sym_gtk_recent_manager_add_item
=
236 (addItemFnc
)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin
, "gtk_recent_manager_add_item");
237 if (sym_gtk_recent_manager_get_default
&& sym_gtk_recent_manager_add_item
)
239 sym_gtk_recent_manager_add_item(sym_gtk_recent_manager_get_default(),
240 rtl::OUStringToOString(rFileUrl
, RTL_TEXTENCODING_UTF8
).getStr());
243 X11SalInstance::AddToRecentDocumentList(rFileUrl
, rMimeType
);
247 GtkYieldMutex::GtkYieldMutex()
251 void GtkYieldMutex::acquire()
253 vos::OThread::TThreadIdentifier aCurrentThread
= vos::OThread::getCurrentIdentifier();
254 // protect member manipulation
256 if( mnCount
> 0 && mnThreadId
== aCurrentThread
)
267 // obtained gdk mutex, now lock count is one by definition
270 mnThreadId
= aCurrentThread
;
274 void GtkYieldMutex::release()
276 vos::OThread::TThreadIdentifier aCurrentThread
= vos::OThread::getCurrentIdentifier();
277 // protect member manipulation
279 // strange things happen, do nothing if we don't own the mutex
280 if( mnThreadId
== aCurrentThread
)
292 sal_Bool
GtkYieldMutex::tryToAcquire()
294 vos::OThread::TThreadIdentifier aCurrentThread
= vos::OThread::getCurrentIdentifier();
295 // protect member manipulation
299 if( mnThreadId
== aCurrentThread
)
313 // HACK: gdk_threads_mutex is private, we shouldn't use it.
314 // how to we do a try_lock without having a gdk_threads_try_enter ?
315 if( ! g_mutex_trylock( gdk_threads_mutex
) )
318 // obtained gdk mutex, now lock count is one by definition
321 mnThreadId
= aCurrentThread
;
327 int GtkYieldMutex::Grab()
329 // this MUST only be called by gdk/gtk callbacks:
330 // they are entered with gdk mutex locked; the mutex
331 // was unlocked by GtkYieldMutex befor yielding which
332 // is now locked again by gtk implicitly
334 // obtained gdk mutex, now lock count is one by definition
337 if( mnCount
== 0 ) // recursive else
338 mnThreadId
= vos::OThread::getCurrentIdentifier();
339 #if OSL_DEBUG_LEVEL > 1
340 else if( mnThreadId
!= vos::OThread::getCurrentIdentifier() )
342 fprintf( stderr
, "Yield mutex grabbed in different thread !\n" );
351 void GtkYieldMutex::Ungrab( int nGrabs
)
353 // this MUST only be called when leaving the callback
354 // that locked the mutex with Grab()