1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <X11/Xatom.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"
38 static bool is_gnome_desktop( Display
* pDisplay
)
42 // warning: these checks are coincidental, GNOME does not
43 // explicitly advertise itself
44 if ( NULL
!= getenv( "GNOME_DESKTOP_SESSION_ID" ) )
49 Atom nAtom1
= XInternAtom( pDisplay
, "GNOME_SM_PROXY", True
);
50 Atom nAtom2
= XInternAtom( pDisplay
, "NAUTILUS_DESKTOP_WINDOW_ID", True
);
51 if( nAtom1
|| nAtom2
)
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
)
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
++ )
85 unsigned long nItems
= 0, nBytes
= 0;
86 unsigned char* pProp
= NULL
;
87 XGetWindowProperty( pDisplay
,
98 if( pProp
&& nType
== nUTFAtom
)
100 OString
aWMName( (sal_Char
*)pProp
);
102 (aWMName
.equalsIgnoreAsciiCase("gnome-shell")) ||
103 (aWMName
.equalsIgnoreAsciiCase("gnome-panel"))
120 static bool bWasXError
= false;
122 static inline bool WasXError()
124 bool bRet
= bWasXError
;
131 static int autodect_error_handler( Display
*, XErrorEvent
* )
137 typedef int(* XErrorHandler
)(Display
*,XErrorEvent
*);
140 static int TDEVersion( Display
* pDisplay
)
144 Atom nFullSession
= XInternAtom( pDisplay
, "TDE_FULL_SESSION", True
);
145 Atom nTDEVersion
= XInternAtom( pDisplay
, "TDE_SESSION_VERSION", True
);
152 Atom aRealType
= None
;
154 unsigned long nItems
= 0;
155 unsigned long nBytesLeft
= 0;
156 unsigned char* pProperty
= NULL
;
157 XGetWindowProperty( pDisplay
,
158 DefaultRootWindow( pDisplay
),
168 if( !WasXError() && nItems
!= 0 && pProperty
)
170 nRet
= *reinterpret_cast< sal_Int32
* >( pProperty
);
181 static int KDEVersion( Display
* pDisplay
)
185 Atom nFullSession
= XInternAtom( pDisplay
, "KDE_FULL_SESSION", True
);
186 Atom nKDEVersion
= XInternAtom( pDisplay
, "KDE_SESSION_VERSION", True
);
193 Atom aRealType
= None
;
195 unsigned long nItems
= 0;
196 unsigned long nBytesLeft
= 0;
197 unsigned char* pProperty
= NULL
;
198 XGetWindowProperty( pDisplay
,
199 DefaultRootWindow( pDisplay
),
209 if( !WasXError() && nItems
!= 0 && pProperty
)
211 nRet
= *reinterpret_cast< sal_Int32
* >( pProperty
);
222 static bool is_tde_desktop( Display
* pDisplay
)
224 if ( NULL
!= getenv( "TDE_FULL_SESSION" ) )
229 if ( TDEVersion( pDisplay
) >= 14 )
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
) )
252 if ( KDEVersion( pDisplay
) == 3 )
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
) )
269 if ( KDEVersion( pDisplay
) == 4 )
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" ) )
288 if ( aOver
.equalsIgnoreAsciiCase( "kde4" ) )
290 if ( aOver
.equalsIgnoreAsciiCase( "gnome" ) )
291 return DESKTOP_GNOME
;
292 if ( aOver
.equalsIgnoreAsciiCase( "unity" ) )
293 return DESKTOP_UNITY
;
294 if ( aOver
.equalsIgnoreAsciiCase( "xfce" ) )
296 if ( aOver
.equalsIgnoreAsciiCase( "mate" ) )
298 if ( aOver
.equalsIgnoreAsciiCase( "kde" ) )
300 if ( aOver
.equalsIgnoreAsciiCase( "none" ) )
301 return DESKTOP_UNKNOWN
;
304 // get display to connect to
305 const char* pDisplayStr
= getenv( "DISPLAY" );
308 rtl::Bootstrap::get("SAL_USE_VCLPLUGIN", plugin
);
310 if (plugin
== "svp" || Application::IsHeadlessModeRequested())
314 int nParams
= rtl_getAppCommandArgCount();
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();
331 if( ! pDisplayStr
|| !*pDisplayStr
)
334 /* #i92121# workaround deadlocks in the X11 implementation
336 static const char* pNoXInitThreads
= getenv( "SAL_NO_XINITTHREADS" );
338 from now on we know that an X connection will be
339 established, so protect X against itself
341 if( ! ( pNoXInitThreads
&& *pNoXInitThreads
) )
344 Display
* pDisplay
= XOpenDisplay( pDisplayStr
);
345 if( pDisplay
== NULL
)
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" ) )
365 else if ( aDesktopSession
.equalsIgnoreAsciiCase( "gnome" ) )
367 else if ( aDesktopSession
.equalsIgnoreAsciiCase( "mate" ) )
369 else if ( aDesktopSession
.equalsIgnoreAsciiCase( "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
) )
376 else if ( is_gnome_desktop( pDisplay
) )
378 else if ( is_kde_desktop( pDisplay
) )
380 else if ( is_tde_desktop( pDisplay
) )
383 ret
= DESKTOP_UNKNOWN
;
385 // set the default handler again
386 XSetErrorHandler( pOldHdl
);
388 XCloseDisplay( pDisplay
);
395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */