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 <unx/svunx.h>
22 : #include <unx/desktops.hxx>
23 : #include <tools/prex.h>
24 : #include <X11/Xatom.h>
25 : #include <tools/postx.h>
26 :
27 : #include "rtl/process.h"
28 : #include "rtl/ustrbuf.hxx"
29 : #include "osl/module.h"
30 : #include "osl/thread.h"
31 : #include "vcl/svapp.hxx"
32 :
33 : #include "vclpluginapi.h"
34 :
35 : #include <unistd.h>
36 : #include <string.h>
37 :
38 : using ::rtl::OUString;
39 : using ::rtl::OString;
40 :
41 0 : static bool is_gnome_desktop( Display* pDisplay )
42 : {
43 0 : bool ret = false;
44 :
45 : // warning: these checks are coincidental, GNOME does not
46 : // explicitly advertise itself
47 :
48 0 : if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
49 0 : ret = true;
50 :
51 0 : if( ! ret )
52 : {
53 0 : Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True );
54 0 : Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True );
55 0 : if( nAtom1 || nAtom2 )
56 : {
57 0 : int nProperties = 0;
58 0 : Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties );
59 0 : if( pProperties && nProperties )
60 : {
61 0 : for( int i = 0; i < nProperties; i++ )
62 0 : if( pProperties[ i ] == nAtom1 ||
63 0 : pProperties[ i ] == nAtom2 )
64 : {
65 0 : ret = true;
66 : }
67 0 : XFree( pProperties );
68 : }
69 : }
70 : }
71 :
72 0 : if( ! ret )
73 : {
74 0 : Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True );
75 0 : Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True );
76 0 : if( nUTFAtom && nNetWMNameAtom )
77 : {
78 : // another, more expensive check: search for a gnome-panel
79 0 : XLIB_Window aRoot, aParent, *pChildren = NULL;
80 0 : unsigned int nChildren = 0;
81 0 : XQueryTree( pDisplay, DefaultRootWindow( pDisplay ),
82 0 : &aRoot, &aParent, &pChildren, &nChildren );
83 0 : if( pChildren && nChildren )
84 : {
85 0 : for( unsigned int i = 0; i < nChildren && ! ret; i++ )
86 : {
87 0 : Atom nType = None;
88 0 : int nFormat = 0;
89 0 : unsigned long nItems = 0, nBytes = 0;
90 0 : unsigned char* pProp = NULL;
91 : XGetWindowProperty( pDisplay,
92 0 : pChildren[i],
93 : nNetWMNameAtom,
94 : 0, 8,
95 : False,
96 : nUTFAtom,
97 : &nType,
98 : &nFormat,
99 : &nItems,
100 : &nBytes,
101 0 : &pProp );
102 0 : if( pProp && nType == nUTFAtom )
103 : {
104 0 : OString aWMName( (sal_Char*)pProp );
105 0 : if (
106 0 : (aWMName.equalsIgnoreAsciiCase("gnome-shell")) ||
107 0 : (aWMName.equalsIgnoreAsciiCase("gnome-panel"))
108 : )
109 : {
110 0 : ret = true;
111 0 : }
112 : }
113 0 : if( pProp )
114 0 : XFree( pProp );
115 : }
116 0 : XFree( pChildren );
117 : }
118 : }
119 : }
120 :
121 0 : return ret;
122 : }
123 :
124 : static bool bWasXError = false;
125 :
126 0 : static inline bool WasXError()
127 : {
128 0 : bool bRet = bWasXError;
129 0 : bWasXError = false;
130 0 : return bRet;
131 : }
132 :
133 : extern "C"
134 : {
135 0 : static int autodect_error_handler( Display*, XErrorEvent* )
136 : {
137 0 : bWasXError = true;
138 0 : return 0;
139 : }
140 :
141 : typedef int(* XErrorHandler)(Display*,XErrorEvent*);
142 : }
143 :
144 0 : static int TDEVersion( Display* pDisplay )
145 : {
146 0 : int nRet = 0;
147 :
148 0 : Atom nFullSession = XInternAtom( pDisplay, "TDE_FULL_SESSION", True );
149 0 : Atom nTDEVersion = XInternAtom( pDisplay, "TDE_SESSION_VERSION", True );
150 :
151 0 : if( nFullSession )
152 : {
153 0 : if( !nTDEVersion )
154 0 : return 14;
155 :
156 0 : Atom aRealType = None;
157 0 : int nFormat = 8;
158 0 : unsigned long nItems = 0;
159 0 : unsigned long nBytesLeft = 0;
160 0 : unsigned char* pProperty = NULL;
161 : XGetWindowProperty( pDisplay,
162 0 : DefaultRootWindow( pDisplay ),
163 : nTDEVersion,
164 : 0, 1,
165 : False,
166 : AnyPropertyType,
167 : &aRealType,
168 : &nFormat,
169 : &nItems,
170 : &nBytesLeft,
171 0 : &pProperty );
172 0 : if( !WasXError() && nItems != 0 && pProperty )
173 : {
174 0 : nRet = *reinterpret_cast< sal_Int32* >( pProperty );
175 : }
176 0 : if( pProperty )
177 : {
178 0 : XFree( pProperty );
179 0 : pProperty = NULL;
180 : }
181 : }
182 0 : return nRet;
183 : }
184 :
185 0 : static int KDEVersion( Display* pDisplay )
186 : {
187 0 : int nRet = 0;
188 :
189 0 : Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True );
190 0 : Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True );
191 :
192 0 : if( nFullSession )
193 : {
194 0 : if( !nKDEVersion )
195 0 : return 3;
196 :
197 0 : Atom aRealType = None;
198 0 : int nFormat = 8;
199 0 : unsigned long nItems = 0;
200 0 : unsigned long nBytesLeft = 0;
201 0 : unsigned char* pProperty = NULL;
202 : XGetWindowProperty( pDisplay,
203 0 : DefaultRootWindow( pDisplay ),
204 : nKDEVersion,
205 : 0, 1,
206 : False,
207 : AnyPropertyType,
208 : &aRealType,
209 : &nFormat,
210 : &nItems,
211 : &nBytesLeft,
212 0 : &pProperty );
213 0 : if( !WasXError() && nItems != 0 && pProperty )
214 : {
215 0 : nRet = *reinterpret_cast< sal_Int32* >( pProperty );
216 : }
217 0 : if( pProperty )
218 : {
219 0 : XFree( pProperty );
220 0 : pProperty = NULL;
221 : }
222 : }
223 0 : return nRet;
224 : }
225 :
226 0 : static bool is_tde_desktop( Display* pDisplay )
227 : {
228 0 : if ( NULL != getenv( "TDE_FULL_SESSION" ) )
229 : {
230 0 : return true; // TDE
231 : }
232 :
233 0 : if ( TDEVersion( pDisplay ) >= 14 )
234 0 : return true;
235 :
236 0 : return false;
237 : }
238 :
239 0 : static bool is_kde_desktop( Display* pDisplay )
240 : {
241 0 : if ( NULL != getenv( "KDE_FULL_SESSION" ) )
242 : {
243 0 : const char *pVer = getenv( "KDE_SESSION_VERSION" );
244 0 : if ( !pVer || pVer[0] == '0' )
245 : {
246 0 : return true; // does not exist => KDE3
247 : }
248 :
249 0 : rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "3" ) );
250 0 : if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
251 : {
252 0 : return true;
253 0 : }
254 : }
255 :
256 0 : if ( KDEVersion( pDisplay ) == 3 )
257 0 : return true;
258 :
259 0 : return false;
260 : }
261 :
262 0 : static bool is_kde4_desktop( Display* pDisplay )
263 : {
264 0 : if ( NULL != getenv( "KDE_FULL_SESSION" ) )
265 : {
266 0 : rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "4" ) );
267 :
268 0 : const char *pVer = getenv( "KDE_SESSION_VERSION" );
269 0 : if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
270 0 : return true;
271 : }
272 :
273 0 : if ( KDEVersion( pDisplay ) == 4 )
274 0 : return true;
275 :
276 0 : return false;
277 : }
278 :
279 : extern "C"
280 : {
281 :
282 11 : DESKTOP_DETECTOR_PUBLIC DesktopType get_desktop_environment()
283 : {
284 11 : static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" );
285 :
286 11 : if ( pOverride && *pOverride )
287 : {
288 0 : OString aOver( pOverride );
289 :
290 0 : if ( aOver.equalsIgnoreAsciiCase( "tde" ) )
291 0 : return DESKTOP_TDE;
292 0 : if ( aOver.equalsIgnoreAsciiCase( "kde4" ) )
293 0 : return DESKTOP_KDE4;
294 0 : if ( aOver.equalsIgnoreAsciiCase( "gnome" ) )
295 0 : return DESKTOP_GNOME;
296 0 : if ( aOver.equalsIgnoreAsciiCase( "kde" ) )
297 0 : return DESKTOP_KDE;
298 0 : if ( aOver.equalsIgnoreAsciiCase( "none" ) )
299 0 : return DESKTOP_UNKNOWN;
300 : }
301 :
302 : // get display to connect to
303 11 : const char* pDisplayStr = getenv( "DISPLAY" );
304 :
305 11 : const char* pUsePlugin = getenv( "SAL_USE_VCLPLUGIN" );
306 :
307 22 : if ((pUsePlugin && (strcmp(pUsePlugin, "svp") == 0))
308 11 : || Application::IsHeadlessModeRequested())
309 11 : pDisplayStr = NULL;
310 : else
311 : {
312 0 : int nParams = rtl_getAppCommandArgCount();
313 0 : OUString aParam;
314 0 : OString aBParm;
315 0 : for( int i = 0; i < nParams; i++ )
316 : {
317 0 : rtl_getAppCommandArg( i, &aParam.pData );
318 0 : if( i < nParams-1 && (aParam == "-display" || aParam == "--display" ) )
319 : {
320 0 : osl_getCommandArg( i+1, &aParam.pData );
321 0 : aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() );
322 0 : pDisplayStr = aBParm.getStr();
323 0 : break;
324 : }
325 0 : }
326 : }
327 :
328 : // no server at all
329 11 : if( ! pDisplayStr || !*pDisplayStr )
330 11 : return DESKTOP_NONE;
331 :
332 : /* #i92121# workaround deadlocks in the X11 implementation
333 : */
334 0 : static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" );
335 : /* #i90094#
336 : from now on we know that an X connection will be
337 : established, so protect X against itself
338 : */
339 0 : if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
340 0 : XInitThreads();
341 :
342 0 : Display* pDisplay = XOpenDisplay( pDisplayStr );
343 0 : if( pDisplay == NULL )
344 0 : return DESKTOP_NONE;
345 :
346 : DesktopType ret;
347 :
348 0 : XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
349 :
350 0 : if ( is_tde_desktop( pDisplay ) )
351 0 : ret = DESKTOP_TDE;
352 0 : else if ( is_kde4_desktop( pDisplay ) )
353 0 : ret = DESKTOP_KDE4;
354 0 : else if ( is_gnome_desktop( pDisplay ) )
355 0 : ret = DESKTOP_GNOME;
356 0 : else if ( is_kde_desktop( pDisplay ) )
357 0 : ret = DESKTOP_KDE;
358 : else
359 0 : ret = DESKTOP_UNKNOWN;
360 :
361 : // set the default handler again
362 0 : XSetErrorHandler( pOldHdl );
363 :
364 0 : XCloseDisplay( pDisplay );
365 :
366 0 : return ret;
367 : }
368 :
369 : }
370 :
371 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|