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