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