Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / vcl / unx / generic / desktopdetect / desktopdetector.cxx
blobaa1c84a30846bf59e6876bb058e6c46b90970fc9
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 <prex.h>
21 #include <X11/Xatom.h>
22 #include <postx.h>
24 #include <unx/desktops.hxx>
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"
33 #include "vclpluginapi.h"
35 #include <unistd.h>
36 #include <string.h>
38 static bool is_gnome_desktop( Display* pDisplay )
40 bool ret = false;
42 // warning: these checks are coincidental, GNOME does not
43 // explicitly advertise itself
44 if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) )
45 ret = true;
47 if( ! ret )
49 Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True );
50 Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True );
51 if( nAtom1 || nAtom2 )
53 int nProperties = 0;
54 Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties );
55 if( pProperties && nProperties )
57 for( int i = 0; i < nProperties; i++ )
58 if( pProperties[ i ] == nAtom1 ||
59 pProperties[ i ] == nAtom2 )
61 ret = true;
63 XFree( pProperties );
68 if( ! ret )
70 Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True );
71 Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True );
72 if( nUTFAtom && nNetWMNameAtom )
74 // another, more expensive check: search for a gnome-panel
75 XLIB_Window aRoot, aParent, *pChildren = NULL;
76 unsigned int nChildren = 0;
77 XQueryTree( pDisplay, DefaultRootWindow( pDisplay ),
78 &aRoot, &aParent, &pChildren, &nChildren );
79 if( pChildren && nChildren )
81 for( unsigned int i = 0; i < nChildren && ! ret; i++ )
83 Atom nType = None;
84 int nFormat = 0;
85 unsigned long nItems = 0, nBytes = 0;
86 unsigned char* pProp = NULL;
87 XGetWindowProperty( pDisplay,
88 pChildren[i],
89 nNetWMNameAtom,
90 0, 8,
91 False,
92 nUTFAtom,
93 &nType,
94 &nFormat,
95 &nItems,
96 &nBytes,
97 &pProp );
98 if( pProp && nType == nUTFAtom )
100 OString aWMName( (sal_Char*)pProp );
101 if (
102 (aWMName.equalsIgnoreAsciiCase("gnome-shell")) ||
103 (aWMName.equalsIgnoreAsciiCase("gnome-panel"))
106 ret = true;
109 if( pProp )
110 XFree( pProp );
112 XFree( pChildren );
117 return ret;
120 static bool bWasXError = false;
122 static inline bool WasXError()
124 bool bRet = bWasXError;
125 bWasXError = false;
126 return bRet;
129 extern "C"
131 static int autodect_error_handler( Display*, XErrorEvent* )
133 bWasXError = true;
134 return 0;
137 typedef int(* XErrorHandler)(Display*,XErrorEvent*);
140 static int TDEVersion( Display* pDisplay )
142 int nRet = 0;
144 Atom nFullSession = XInternAtom( pDisplay, "TDE_FULL_SESSION", True );
145 Atom nTDEVersion = XInternAtom( pDisplay, "TDE_SESSION_VERSION", True );
147 if( nFullSession )
149 if( !nTDEVersion )
150 return 14;
152 Atom aRealType = None;
153 int nFormat = 8;
154 unsigned long nItems = 0;
155 unsigned long nBytesLeft = 0;
156 unsigned char* pProperty = NULL;
157 XGetWindowProperty( pDisplay,
158 DefaultRootWindow( pDisplay ),
159 nTDEVersion,
160 0, 1,
161 False,
162 AnyPropertyType,
163 &aRealType,
164 &nFormat,
165 &nItems,
166 &nBytesLeft,
167 &pProperty );
168 if( !WasXError() && nItems != 0 && pProperty )
170 nRet = *reinterpret_cast< sal_Int32* >( pProperty );
172 if( pProperty )
174 XFree( pProperty );
175 pProperty = NULL;
178 return nRet;
181 static int KDEVersion( Display* pDisplay )
183 int nRet = 0;
185 Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True );
186 Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True );
188 if( nFullSession )
190 if( !nKDEVersion )
191 return 3;
193 Atom aRealType = None;
194 int nFormat = 8;
195 unsigned long nItems = 0;
196 unsigned long nBytesLeft = 0;
197 unsigned char* pProperty = NULL;
198 XGetWindowProperty( pDisplay,
199 DefaultRootWindow( pDisplay ),
200 nKDEVersion,
201 0, 1,
202 False,
203 AnyPropertyType,
204 &aRealType,
205 &nFormat,
206 &nItems,
207 &nBytesLeft,
208 &pProperty );
209 if( !WasXError() && nItems != 0 && pProperty )
211 nRet = *reinterpret_cast< sal_Int32* >( pProperty );
213 if( pProperty )
215 XFree( pProperty );
216 pProperty = NULL;
219 return nRet;
222 static bool is_tde_desktop( Display* pDisplay )
224 if ( NULL != getenv( "TDE_FULL_SESSION" ) )
226 return true; // TDE
229 if ( TDEVersion( pDisplay ) >= 14 )
230 return true;
232 return false;
235 static bool is_kde_desktop( Display* pDisplay )
237 if ( NULL != getenv( "KDE_FULL_SESSION" ) )
239 const char *pVer = getenv( "KDE_SESSION_VERSION" );
240 if ( !pVer || pVer[0] == '0' )
242 return true; // does not exist => KDE3
245 OUString aVer( "3" );
246 if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
248 return true;
252 if ( KDEVersion( pDisplay ) == 3 )
253 return true;
255 return false;
258 static bool is_kde4_desktop( Display* pDisplay )
260 if ( NULL != getenv( "KDE_FULL_SESSION" ) )
262 OUString aVer( "4" );
264 const char *pVer = getenv( "KDE_SESSION_VERSION" );
265 if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) )
266 return true;
269 if ( KDEVersion( pDisplay ) == 4 )
270 return true;
272 return false;
275 extern "C"
278 DESKTOP_DETECTOR_PUBLIC DesktopType get_desktop_environment()
280 static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" );
282 if ( pOverride && *pOverride )
284 OString aOver( pOverride );
286 if ( aOver.equalsIgnoreAsciiCase( "tde" ) )
287 return DESKTOP_TDE;
288 if ( aOver.equalsIgnoreAsciiCase( "kde4" ) )
289 return DESKTOP_KDE4;
290 if ( aOver.equalsIgnoreAsciiCase( "gnome" ) )
291 return DESKTOP_GNOME;
292 if ( aOver.equalsIgnoreAsciiCase( "unity" ) )
293 return DESKTOP_UNITY;
294 if ( aOver.equalsIgnoreAsciiCase( "xfce" ) )
295 return DESKTOP_XFCE;
296 if ( aOver.equalsIgnoreAsciiCase( "mate" ) )
297 return DESKTOP_MATE;
298 if ( aOver.equalsIgnoreAsciiCase( "kde" ) )
299 return DESKTOP_KDE;
300 if ( aOver.equalsIgnoreAsciiCase( "none" ) )
301 return DESKTOP_UNKNOWN;
304 // get display to connect to
305 const char* pDisplayStr = getenv( "DISPLAY" );
307 OUString plugin;
308 rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", plugin);
310 if (plugin == "svp" || Application::IsHeadlessModeRequested())
311 pDisplayStr = NULL;
312 else
314 int nParams = rtl_getAppCommandArgCount();
315 OUString aParam;
316 OString aBParm;
317 for( int i = 0; i < nParams; i++ )
319 rtl_getAppCommandArg( i, &aParam.pData );
320 if( i < nParams-1 && (aParam == "-display" || aParam == "--display" ) )
322 rtl_getAppCommandArg( i+1, &aParam.pData );
323 aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() );
324 pDisplayStr = aBParm.getStr();
325 break;
330 // no server at all
331 if( ! pDisplayStr || !*pDisplayStr )
332 return DESKTOP_NONE;
334 /* #i92121# workaround deadlocks in the X11 implementation
336 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
341 if( ! ( pNoXInitThreads && *pNoXInitThreads ) )
342 XInitThreads();
344 Display* pDisplay = XOpenDisplay( pDisplayStr );
345 if( pDisplay == NULL )
346 return DESKTOP_NONE;
348 DesktopType ret;
350 XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler );
352 const char *pSession;
353 OString aDesktopSession;
354 if ( ( pSession = getenv( "DESKTOP_SESSION" ) ) )
355 aDesktopSession = OString( pSession, strlen( pSession ) );
357 const char *pDesktop;
358 OString aCurrentDesktop;
359 if ( ( pDesktop = getenv( "XDG_CURRENT_DESKTOP" ) ) )
360 aCurrentDesktop = OString( pDesktop, strlen( pDesktop ) );
362 // fast environment variable checks
363 if ( aCurrentDesktop.equalsIgnoreAsciiCase( "unity" ) )
364 ret = DESKTOP_UNITY;
365 else if ( aDesktopSession.equalsIgnoreAsciiCase( "gnome" ) )
366 ret = DESKTOP_GNOME;
367 else if ( aDesktopSession.equalsIgnoreAsciiCase( "mate" ) )
368 ret = DESKTOP_MATE;
369 else if ( aDesktopSession.equalsIgnoreAsciiCase( "xfce" ) )
370 ret = DESKTOP_XFCE;
372 // these guys can be slower, with X property fetches,
373 // round-trips etc. and so are done later.
374 else if ( is_kde4_desktop( pDisplay ) )
375 ret = DESKTOP_KDE4;
376 else if ( is_gnome_desktop( pDisplay ) )
377 ret = DESKTOP_GNOME;
378 else if ( is_kde_desktop( pDisplay ) )
379 ret = DESKTOP_KDE;
380 else if ( is_tde_desktop( pDisplay ) )
381 ret = DESKTOP_TDE;
382 else
383 ret = DESKTOP_UNKNOWN;
385 // set the default handler again
386 XSetErrorHandler( pOldHdl );
388 XCloseDisplay( pDisplay );
390 return ret;
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */