1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <unx/svunx.h> 32 #include <tools/prex.h> 33 #include <X11/Xatom.h> 34 #include <tools/postx.h> 35 36 #include "rtl/ustrbuf.hxx" 37 #include "osl/module.h" 38 #include "osl/process.h" 39 #include "osl/thread.h" 40 41 #include "vclpluginapi.h" 42 43 #include <unistd.h> 44 45 using namespace rtl; 46 47 enum { 48 DESKTOP_NONE = 0, 49 DESKTOP_UNKNOWN, 50 DESKTOP_GNOME, 51 DESKTOP_KDE, 52 DESKTOP_KDE4, 53 DESKTOP_CDE 54 }; 55 56 static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" }; 57 58 static bool is_gnome_desktop( Display* pDisplay ) 59 { 60 bool ret = false; 61 62 // warning: these checks are coincidental, GNOME does not 63 // explicitly advertise itself 64 65 if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) ) 66 ret = true; 67 68 if( ! ret ) 69 { 70 Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True ); 71 Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True ); 72 if( nAtom1 || nAtom2 ) 73 { 74 int nProperties = 0; 75 Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties ); 76 if( pProperties && nProperties ) 77 { 78 for( int i = 0; i < nProperties; i++ ) 79 if( pProperties[ i ] == nAtom1 || 80 pProperties[ i ] == nAtom2 ) 81 { 82 ret = true; 83 } 84 XFree( pProperties ); 85 } 86 } 87 } 88 89 if( ! ret ) 90 { 91 Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True ); 92 Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True ); 93 if( nUTFAtom && nNetWMNameAtom ) 94 { 95 // another, more expensive check: search for a gnome-panel 96 XLIB_Window aRoot, aParent, *pChildren = NULL; 97 unsigned int nChildren = 0; 98 XQueryTree( pDisplay, DefaultRootWindow( pDisplay ), 99 &aRoot, &aParent, &pChildren, &nChildren ); 100 if( pChildren && nChildren ) 101 { 102 for( unsigned int i = 0; i < nChildren && ! ret; i++ ) 103 { 104 Atom nType = None; 105 int nFormat = 0; 106 unsigned long nItems = 0, nBytes = 0; 107 unsigned char* pProp = NULL; 108 XGetWindowProperty( pDisplay, 109 pChildren[i], 110 nNetWMNameAtom, 111 0, 8, 112 False, 113 nUTFAtom, 114 &nType, 115 &nFormat, 116 &nItems, 117 &nBytes, 118 &pProp ); 119 if( pProp && nType == nUTFAtom ) 120 { 121 OString aWMName( (sal_Char*)pProp ); 122 if( aWMName.equalsIgnoreAsciiCase( "gnome-panel" ) ) 123 ret = true; 124 } 125 if( pProp ) 126 XFree( pProp ); 127 } 128 XFree( pChildren ); 129 } 130 } 131 } 132 133 return ret; 134 } 135 136 static bool bWasXError = false; 137 138 static inline bool WasXError() 139 { 140 bool bRet = bWasXError; 141 bWasXError = false; 142 return bRet; 143 } 144 145 extern "C" 146 { 147 static int autodect_error_handler( Display*, XErrorEvent* ) 148 { 149 bWasXError = true; 150 return 0; 151 } 152 153 typedef int(* XErrorHandler)(Display*,XErrorEvent*); 154 } 155 156 static int KDEVersion( Display* pDisplay ) 157 { 158 int nRet = 0; 159 160 Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True ); 161 Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True ); 162 163 if( nFullSession ) 164 { 165 if( !nKDEVersion ) 166 return 3; 167 168 Atom aRealType = None; 169 int nFormat = 8; 170 unsigned long nItems = 0; 171 unsigned long nBytesLeft = 0; 172 unsigned char* pProperty = NULL; 173 XGetWindowProperty( pDisplay, 174 DefaultRootWindow( pDisplay ), 175 nKDEVersion, 176 0, 1, 177 False, 178 AnyPropertyType, 179 &aRealType, 180 &nFormat, 181 &nItems, 182 &nBytesLeft, 183 &pProperty ); 184 if( !WasXError() && nItems != 0 && pProperty ) 185 { 186 nRet = *reinterpret_cast< sal_Int32* >( pProperty ); 187 } 188 if( pProperty ) 189 { 190 XFree( pProperty ); 191 pProperty = NULL; 192 } 193 } 194 return nRet; 195 } 196 197 static bool is_kde_desktop( Display* pDisplay ) 198 { 199 if ( NULL != getenv( "KDE_FULL_SESSION" ) ) 200 { 201 const char *pVer = getenv( "KDE_SESSION_VERSION" ); 202 if ( !pVer || pVer[0] == '0' ) 203 { 204 return true; // does not exist => KDE3 205 } 206 207 rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "3" ) ); 208 if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) ) 209 { 210 return true; 211 } 212 } 213 214 if ( KDEVersion( pDisplay ) == 3 ) 215 return true; 216 217 return false; 218 } 219 220 static bool is_kde4_desktop( Display* pDisplay ) 221 { 222 if ( NULL != getenv( "KDE_FULL_SESSION" ) ) 223 { 224 rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "4" ) ); 225 226 const char *pVer = getenv( "KDE_SESSION_VERSION" ); 227 if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) ) 228 return true; 229 } 230 231 if ( KDEVersion( pDisplay ) == 4 ) 232 return true; 233 234 return false; 235 } 236 237 static bool is_cde_desktop( Display* pDisplay ) 238 { 239 void* pLibrary = NULL; 240 241 Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True ); 242 OUString aPathName( RTL_CONSTASCII_USTRINGPARAM( "file:///usr/dt/lib/libDtSvc.so" ) ); 243 if( nDtAtom && ( pLibrary = osl_loadModule( aPathName.pData, SAL_LOADMODULE_DEFAULT ) ) ) 244 { 245 osl_unloadModule( (oslModule)pLibrary ); 246 return true; 247 } 248 249 return false; 250 } 251 252 253 extern "C" 254 { 255 256 DESKTOP_DETECTOR_PUBLIC rtl::OUString get_desktop_environment() 257 { 258 rtl::OUStringBuffer aRet( 8 ); 259 static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" ); 260 261 if ( pOverride && *pOverride ) 262 { 263 OString aOver( pOverride ); 264 265 if ( aOver.equalsIgnoreAsciiCase( "cde" ) ) 266 aRet.appendAscii( desktop_strings[DESKTOP_CDE] ); 267 if ( aOver.equalsIgnoreAsciiCase( "kde4" ) ) 268 aRet.appendAscii( desktop_strings[DESKTOP_KDE4] ); 269 if ( aOver.equalsIgnoreAsciiCase( "gnome" ) ) 270 aRet.appendAscii( desktop_strings[DESKTOP_GNOME] ); 271 if ( aOver.equalsIgnoreAsciiCase( "kde" ) ) 272 aRet.appendAscii( desktop_strings[DESKTOP_KDE] ); 273 if ( aOver.equalsIgnoreAsciiCase( "none" ) ) 274 aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] ); 275 } 276 277 if( aRet.getLength() == 0 ) 278 { 279 // get display to connect to 280 const char* pDisplayStr = getenv( "DISPLAY" ); 281 int nParams = osl_getCommandArgCount(); 282 OUString aParam; 283 OString aBParm; 284 for( int i = 0; i < nParams; i++ ) 285 { 286 osl_getCommandArg( i, &aParam.pData ); 287 if( aParam.equalsAscii( "-headless" ) ) 288 { 289 pDisplayStr = NULL; 290 break; 291 } 292 if( i < nParams-1 && (aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" )) ) 293 { 294 osl_getCommandArg( i+1, &aParam.pData ); 295 aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() ); 296 pDisplayStr = aBParm.getStr(); 297 break; 298 } 299 } 300 301 // no server at all 302 if( ! pDisplayStr || !*pDisplayStr ) 303 aRet.appendAscii( desktop_strings[DESKTOP_NONE] ); 304 else 305 { 306 /* #i92121# workaround deadlocks in the X11 implementation 307 */ 308 static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); 309 /* #i90094# 310 from now on we know that an X connection will be 311 established, so protect X against itself 312 */ 313 if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) 314 XInitThreads(); 315 316 Display* pDisplay = XOpenDisplay( pDisplayStr ); 317 if( pDisplay ) 318 { 319 XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler ); 320 321 if ( is_kde4_desktop( pDisplay ) ) 322 aRet.appendAscii( desktop_strings[DESKTOP_KDE4] ); 323 else if ( is_gnome_desktop( pDisplay ) ) 324 aRet.appendAscii( desktop_strings[DESKTOP_GNOME] ); 325 else if ( is_cde_desktop( pDisplay ) ) 326 aRet.appendAscii( desktop_strings[DESKTOP_CDE] ); 327 else if ( is_kde_desktop( pDisplay ) ) 328 aRet.appendAscii( desktop_strings[DESKTOP_KDE] ); 329 else 330 aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] ); 331 332 // set the default handler again 333 XSetErrorHandler( pOldHdl ); 334 335 XCloseDisplay( pDisplay ); 336 } 337 } 338 } 339 340 return aRet.makeStringAndClear(); 341 } 342 343 } 344