Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include <stack>
22 : #include <string.h>
23 : #include <osl/module.h>
24 : #include <unx/gtk/gtkdata.hxx>
25 : #include <unx/gtk/gtkinst.hxx>
26 : #include <unx/salobj.h>
27 : #include <unx/gtk/gtkframe.hxx>
28 : #include <unx/gtk/gtkobject.hxx>
29 : #include <unx/gtk/atkbridge.hxx>
30 : #include <unx/gtk/gtkprn.hxx>
31 : #include <unx/gtk/gtksalmenu.hxx>
32 : #include <headless/svpvd.hxx>
33 : #include <headless/svpbmp.hxx>
34 : #include <vcl/apptypes.hxx>
35 : #include <generic/genpspgraphics.h>
36 : #include <rtl/strbuf.hxx>
37 :
38 : #include <rtl/uri.hxx>
39 :
40 : #if OSL_DEBUG_LEVEL > 1
41 : #include <stdio.h>
42 : #endif
43 :
44 : #include <dlfcn.h>
45 : #include <fcntl.h>
46 : #include <unistd.h>
47 :
48 : #include "gtkprintwrapper.hxx"
49 :
50 : extern "C"
51 : {
52 : #define GET_YIELD_MUTEX() static_cast<GtkYieldMutex*>(GetSalData()->m_pInstance->GetYieldMutex())
53 0 : static void GdkThreadsEnter( void )
54 : {
55 0 : GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
56 0 : pYieldMutex->ThreadsEnter();
57 0 : }
58 0 : static void GdkThreadsLeave( void )
59 : {
60 0 : GtkYieldMutex *pYieldMutex = GET_YIELD_MUTEX();
61 0 : pYieldMutex->ThreadsLeave();
62 0 : }
63 :
64 0 : VCLPLUG_GTK_PUBLIC SalInstance* create_SalInstance( oslModule )
65 : {
66 : #if OSL_DEBUG_LEVEL > 1
67 : fprintf( stderr, "create vcl plugin instance with gtk version %d %d %d\n",
68 : (int) gtk_major_version, (int) gtk_minor_version,
69 : (int) gtk_micro_version );
70 : #endif
71 0 : if( gtk_major_version < 2 || // very unlikely sanity check
72 0 : ( gtk_major_version == 2 && gtk_minor_version < 4 ) )
73 : {
74 0 : g_warning("require a newer gtk than %d.%d for gdk_threads_set_lock_functions", (int) gtk_major_version, gtk_minor_version);
75 0 : return NULL;
76 : }
77 :
78 : /* #i92121# workaround deadlocks in the X11 implementation
79 : */
80 0 : static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
81 : /* #i90094#
82 : from now on we know that an X connection will be
83 : established, so protect X against itself
84 : */
85 0 : if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
86 0 : XInitThreads();
87 :
88 : #if GTK_CHECK_VERSION(3,0,0)
89 : const gchar* pVersion = gtk_check_version( 3, 2, 0 );
90 : #else
91 0 : const gchar* pVersion = gtk_check_version( 2, 2, 0 );
92 : #endif
93 0 : if( pVersion )
94 : {
95 : #if OSL_DEBUG_LEVEL > 1
96 : fprintf( stderr, "gtk version conflict: %s\n", pVersion );
97 : #endif
98 0 : return NULL;
99 : }
100 :
101 : GtkYieldMutex *pYieldMutex;
102 :
103 : // init gdk thread protection
104 : if ( !g_thread_supported() )
105 : g_thread_init( NULL );
106 :
107 : #if !GTK_CHECK_VERSION(2,4,0)
108 : #error "Requires gtk 2.4.0+ for lock hooking"
109 : #endif
110 0 : gdk_threads_set_lock_functions (GdkThreadsEnter, GdkThreadsLeave);
111 :
112 : #if OSL_DEBUG_LEVEL > 1
113 : fprintf( stderr, "Hooked gdk threads locks\n" );
114 : #endif
115 :
116 0 : pYieldMutex = new GtkYieldMutex();
117 :
118 0 : gdk_threads_init();
119 :
120 0 : GtkInstance* pInstance = new GtkInstance( pYieldMutex );
121 : #if OSL_DEBUG_LEVEL > 1
122 : fprintf( stderr, "creating GtkSalInstance 0x%p\n", pInstance );
123 : #endif
124 :
125 : // initialize SalData
126 0 : GtkData *pSalData = new GtkData( pInstance );
127 0 : pSalData->Init();
128 0 : pSalData->initNWF();
129 :
130 0 : pInstance->Init();
131 :
132 0 : InitAtkBridge();
133 :
134 0 : return pInstance;
135 : }
136 : }
137 :
138 : #if GTK_CHECK_VERSION(3,0,0)
139 : static sal_uInt16 categorizeEvent(const GdkEvent *pEvent)
140 : {
141 : sal_uInt16 nType = 0;
142 : switch( pEvent->type )
143 : {
144 : case GDK_MOTION_NOTIFY:
145 : case GDK_BUTTON_PRESS:
146 : case GDK_2BUTTON_PRESS:
147 : case GDK_3BUTTON_PRESS:
148 : case GDK_BUTTON_RELEASE:
149 : case GDK_ENTER_NOTIFY:
150 : case GDK_LEAVE_NOTIFY:
151 : case GDK_SCROLL:
152 : nType = VCL_INPUT_MOUSE;
153 : break;
154 : case GDK_KEY_PRESS:
155 : case GDK_KEY_RELEASE:
156 : nType = VCL_INPUT_KEYBOARD;
157 : break;
158 : case GDK_EXPOSE:
159 : nType = VCL_INPUT_PAINT;
160 : break;
161 : default:
162 : nType = VCL_INPUT_OTHER;
163 : break;
164 : }
165 : return nType;
166 : }
167 : #endif
168 :
169 0 : GtkInstance::GtkInstance( SalYieldMutex* pMutex )
170 : #if GTK_CHECK_VERSION(3,0,0)
171 : : SvpSalInstance( pMutex )
172 : #else
173 0 : : X11SalInstance( pMutex )
174 : #endif
175 : {
176 0 : }
177 :
178 : // This has to happen after gtk_init has been called by saldata.cxx's
179 : // Init or our handlers just get clobbered.
180 0 : void GtkInstance::Init()
181 : {
182 0 : }
183 :
184 0 : GtkInstance::~GtkInstance()
185 : {
186 0 : while( !m_aTimers.empty() )
187 0 : delete *m_aTimers.begin();
188 0 : DeInitAtkBridge();
189 0 : }
190 :
191 0 : SalFrame* GtkInstance::CreateFrame( SalFrame* pParent, sal_uLong nStyle )
192 : {
193 0 : return new GtkSalFrame( pParent, nStyle );
194 : }
195 :
196 0 : SalFrame* GtkInstance::CreateChildFrame( SystemParentData* pParentData, sal_uLong )
197 : {
198 0 : return new GtkSalFrame( pParentData );
199 : }
200 :
201 0 : SalObject* GtkInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, sal_Bool bShow )
202 : {
203 : #if !GTK_CHECK_VERSION(3,0,0)
204 : // there is no method to set a visual for a GtkWidget
205 : // so we need the X11SalObject in that case
206 0 : if( pWindowData )
207 0 : return X11SalObject::CreateObject( pParent, pWindowData, bShow );
208 : #else
209 : (void)pWindowData;
210 : #warning FIXME: Missing CreateObject functionality ...
211 : #endif
212 :
213 0 : return new GtkSalObject( static_cast<GtkSalFrame*>(pParent), bShow );
214 : }
215 :
216 : extern "C"
217 : {
218 : typedef void*(* getDefaultFnc)();
219 : typedef void(* addItemFnc)(void *, const char *);
220 : }
221 :
222 0 : void GtkInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& rMimeType)
223 : {
224 0 : OString sGtkURL;
225 0 : rtl_TextEncoding aSystemEnc = osl_getThreadTextEncoding();
226 0 : if ((aSystemEnc == RTL_TEXTENCODING_UTF8) || !rFileUrl.startsWith( "file://" ))
227 0 : sGtkURL = OUStringToOString(rFileUrl, RTL_TEXTENCODING_UTF8);
228 : else
229 : {
230 : //Non-utf8 locales are a bad idea if trying to work with non-ascii filenames
231 : //Decode %XX components
232 0 : OUString sDecodedUri = rtl::Uri::decode(rFileUrl.copy(7), rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8);
233 : //Convert back to system locale encoding
234 0 : OString sSystemUrl = OUStringToOString(sDecodedUri, aSystemEnc);
235 : //Encode to an escaped ASCII-encoded URI
236 0 : gchar *g_uri = g_filename_to_uri(sSystemUrl.getStr(), NULL, NULL);
237 0 : sGtkURL = OString(g_uri);
238 0 : g_free(g_uri);
239 : }
240 : #if GTK_CHECK_VERSION(2,10,0)
241 0 : GtkRecentManager *manager = gtk_recent_manager_get_default ();
242 0 : gtk_recent_manager_add_item (manager, sGtkURL.getStr());
243 0 : (void)rMimeType;
244 : #else
245 : static getDefaultFnc sym_gtk_recent_manager_get_default =
246 : (getDefaultFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_get_default" );
247 :
248 : static addItemFnc sym_gtk_recent_manager_add_item =
249 : (addItemFnc)osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gtk_recent_manager_add_item");
250 : if (sym_gtk_recent_manager_get_default && sym_gtk_recent_manager_add_item)
251 : sym_gtk_recent_manager_add_item(sym_gtk_recent_manager_get_default(), sGtkURL.getStr());
252 : else
253 : X11SalInstance::AddToRecentDocumentList(rFileUrl, rMimeType);
254 : #endif
255 0 : }
256 :
257 0 : SalInfoPrinter* GtkInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
258 : ImplJobSetup* pSetupData )
259 : {
260 : #if defined ENABLE_GTK_PRINT || GTK_CHECK_VERSION(3,0,0)
261 0 : mbPrinterInit = true;
262 : // create and initialize SalInfoPrinter
263 0 : PspSalInfoPrinter* pPrinter = new GtkSalInfoPrinter;
264 0 : configurePspInfoPrinter(pPrinter, pQueueInfo, pSetupData);
265 0 : return pPrinter;
266 : #else
267 : return Superclass_t::CreateInfoPrinter( pQueueInfo, pSetupData );
268 : #endif
269 : }
270 :
271 0 : SalPrinter* GtkInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
272 : {
273 : #if defined ENABLE_GTK_PRINT || GTK_CHECK_VERSION(3,0,0)
274 0 : mbPrinterInit = true;
275 0 : return new GtkSalPrinter( pInfoPrinter );
276 : #else
277 : return Superclass_t::CreatePrinter( pInfoPrinter );
278 : #endif
279 : }
280 :
281 :
282 0 : GtkYieldMutex::GtkYieldMutex()
283 : {
284 0 : }
285 :
286 0 : void GtkYieldMutex::acquire()
287 : {
288 0 : SalYieldMutex::acquire();
289 0 : }
290 :
291 0 : void GtkYieldMutex::release()
292 : {
293 0 : SalYieldMutex::release();
294 0 : }
295 :
296 : /*
297 : * These methods always occur in pairs
298 : * A ThreadsEnter is followed by a ThreadsLeave
299 : * We need to queue up the recursive lock count
300 : * for each pair, so we can accurately restore
301 : * it later.
302 : */
303 0 : void GtkYieldMutex::ThreadsEnter()
304 : {
305 0 : acquire();
306 0 : if( !aYieldStack.empty() )
307 : { /* Previously called ThreadsLeave() */
308 0 : sal_uLong nCount = aYieldStack.front();
309 0 : aYieldStack.pop_front();
310 0 : while( nCount-- > 1 )
311 0 : acquire();
312 : }
313 0 : }
314 :
315 0 : void GtkYieldMutex::ThreadsLeave()
316 : {
317 0 : aYieldStack.push_front( mnCount );
318 :
319 : #if OSL_DEBUG_LEVEL > 1
320 : if( mnThreadId &&
321 : mnThreadId != osl::Thread::getCurrentIdentifier())
322 : fprintf( stderr, "\n\n--- A different thread owns the mutex ...---\n\n\n");
323 : #endif
324 :
325 0 : while( mnCount > 1 )
326 0 : release();
327 0 : release();
328 0 : }
329 :
330 0 : SalVirtualDevice* GtkInstance::CreateVirtualDevice( SalGraphics *pG,
331 : long nDX, long nDY,
332 : sal_uInt16 nBitCount,
333 : const SystemGraphicsData *pGd )
334 : {
335 : #if GTK_CHECK_VERSION(3,0,0)
336 : (void)pG; (void) pGd;
337 : SvpSalVirtualDevice* pNew = new SvpSalVirtualDevice( nBitCount );
338 : pNew->SetSize( nDX, nDY );
339 : return pNew;
340 : #else
341 0 : return X11SalInstance::CreateVirtualDevice( pG, nDX, nDY, nBitCount, pGd );
342 : #endif
343 : }
344 :
345 0 : SalBitmap* GtkInstance::CreateSalBitmap()
346 : {
347 : #if GTK_CHECK_VERSION(3,0,0)
348 : return new SvpSalBitmap();
349 : #else
350 0 : return X11SalInstance::CreateSalBitmap();
351 : #endif
352 : }
353 :
354 : #ifdef ENABLE_GMENU_INTEGRATION
355 :
356 0 : SalMenu* GtkInstance::CreateMenu( sal_Bool bMenuBar, Menu* pVCLMenu )
357 : {
358 0 : GtkSalMenu* pSalMenu = new GtkSalMenu( bMenuBar );
359 0 : pSalMenu->SetMenu( pVCLMenu );
360 0 : return pSalMenu;
361 : }
362 :
363 0 : void GtkInstance::DestroyMenu( SalMenu* pMenu )
364 : {
365 0 : delete pMenu;
366 0 : }
367 :
368 0 : SalMenuItem* GtkInstance::CreateMenuItem( const SalItemParams* pItemData )
369 : {
370 0 : return new GtkSalMenuItem( pItemData );
371 : }
372 :
373 0 : void GtkInstance::DestroyMenuItem( SalMenuItem* pItem )
374 : {
375 0 : delete pItem;
376 0 : }
377 :
378 : #else // not ENABLE_GMENU_INTEGRATION
379 :
380 : SalMenu* GtkInstance::CreateMenu( sal_Bool, Menu* ) { return NULL; }
381 : void GtkInstance::DestroyMenu( SalMenu* ) {}
382 : SalMenuItem* GtkInstance::CreateMenuItem( const SalItemParams* ) { return NULL; }
383 : void GtkInstance::DestroyMenuItem( SalMenuItem* ) {}
384 :
385 : #endif
386 :
387 0 : SalTimer* GtkInstance::CreateSalTimer()
388 : {
389 0 : GtkSalTimer *pTimer = new GtkSalTimer();
390 0 : m_aTimers.push_back( pTimer );
391 0 : return pTimer;
392 : }
393 :
394 0 : void GtkInstance::RemoveTimer (SalTimer *pTimer)
395 : {
396 0 : std::vector<GtkSalTimer *>::iterator it;
397 0 : it = std::find( m_aTimers.begin(), m_aTimers.end(), pTimer );
398 0 : if( it != m_aTimers.end() )
399 0 : m_aTimers.erase( it );
400 0 : }
401 :
402 0 : void GtkInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
403 : {
404 0 : GetGtkSalData()->Yield( bWait, bHandleAllCurrentEvents );
405 0 : }
406 :
407 0 : bool GtkInstance::IsTimerExpired()
408 : {
409 0 : for( std::vector<GtkSalTimer *>::iterator it = m_aTimers.begin();
410 0 : it != m_aTimers.end(); ++it )
411 0 : if( (*it)->Expired() )
412 0 : return true;
413 :
414 0 : return false;
415 : }
416 :
417 0 : bool GtkInstance::AnyInput( sal_uInt16 nType )
418 : {
419 0 : if( (nType & VCL_INPUT_TIMER) && IsTimerExpired() )
420 0 : return true;
421 : #if !GTK_CHECK_VERSION(3,0,0)
422 0 : bool bRet = X11SalInstance::AnyInput(nType);
423 : #else
424 : if (!gdk_events_pending())
425 : return false;
426 :
427 : if (nType == VCL_INPUT_ANY)
428 : return true;
429 :
430 : bool bRet = false;
431 : std::stack<GdkEvent*> aEvents;
432 : GdkEvent *pEvent = NULL;
433 : while ((pEvent = gdk_event_get()))
434 : {
435 : aEvents.push(pEvent);
436 : sal_uInt16 nEventType = categorizeEvent(pEvent);
437 : if ( (nEventType & nType) || ( ! nEventType && (nType & VCL_INPUT_OTHER) ) )
438 : {
439 : bRet = true;
440 : break;
441 : }
442 : }
443 :
444 : while (!aEvents.empty())
445 : {
446 : pEvent = aEvents.top();
447 : gdk_event_put(pEvent);
448 : gdk_event_free(pEvent);
449 : aEvents.pop();
450 : }
451 : #endif
452 0 : return bRet;
453 : }
454 :
455 0 : GenPspGraphics *GtkInstance::CreatePrintGraphics()
456 : {
457 0 : return new GenPspGraphics();
458 : }
459 :
460 : boost::shared_ptr<vcl::unx::GtkPrintWrapper>
461 0 : GtkInstance::getPrintWrapper() const
462 : {
463 0 : if (!m_pPrintWrapper)
464 0 : m_pPrintWrapper.reset(new vcl::unx::GtkPrintWrapper);
465 0 : return m_pPrintWrapper;
466 0 : }
467 :
468 : #if GTK_CHECK_VERSION(3,0,0)
469 : #include "../../../headless/svpinst.cxx"
470 : #endif
471 :
472 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|