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