| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_vcl.hxx" |
| |
| #include <unx/svunx.h> |
| #include <tools/prex.h> |
| #include <X11/Xatom.h> |
| #include <tools/postx.h> |
| |
| #include "rtl/ustrbuf.hxx" |
| #include "osl/module.h" |
| #include "osl/process.h" |
| #include "osl/thread.h" |
| |
| #include "vclpluginapi.h" |
| |
| #include <unistd.h> |
| |
| using namespace rtl; |
| |
| enum { |
| DESKTOP_NONE = 0, |
| DESKTOP_UNKNOWN, |
| DESKTOP_GNOME, |
| DESKTOP_KDE, |
| DESKTOP_KDE4, |
| DESKTOP_CDE |
| }; |
| |
| static const char * desktop_strings[] = { "none", "unknown", "GNOME", "KDE", "KDE4", "CDE" }; |
| |
| static bool is_gnome_desktop( Display* pDisplay ) |
| { |
| bool ret = false; |
| |
| // warning: these checks are coincidental, GNOME does not |
| // explicitly advertise itself |
| |
| if ( NULL != getenv( "GNOME_DESKTOP_SESSION_ID" ) ) |
| ret = true; |
| |
| if( ! ret ) |
| { |
| Atom nAtom1 = XInternAtom( pDisplay, "GNOME_SM_PROXY", True ); |
| Atom nAtom2 = XInternAtom( pDisplay, "NAUTILUS_DESKTOP_WINDOW_ID", True ); |
| if( nAtom1 || nAtom2 ) |
| { |
| int nProperties = 0; |
| Atom* pProperties = XListProperties( pDisplay, DefaultRootWindow( pDisplay ), &nProperties ); |
| if( pProperties && nProperties ) |
| { |
| for( int i = 0; i < nProperties; i++ ) |
| if( pProperties[ i ] == nAtom1 || |
| pProperties[ i ] == nAtom2 ) |
| { |
| ret = true; |
| } |
| XFree( pProperties ); |
| } |
| } |
| } |
| |
| if( ! ret ) |
| { |
| Atom nUTFAtom = XInternAtom( pDisplay, "UTF8_STRING", True ); |
| Atom nNetWMNameAtom = XInternAtom( pDisplay, "_NET_WM_NAME", True ); |
| if( nUTFAtom && nNetWMNameAtom ) |
| { |
| // another, more expensive check: search for a gnome-panel |
| XLIB_Window aRoot, aParent, *pChildren = NULL; |
| unsigned int nChildren = 0; |
| XQueryTree( pDisplay, DefaultRootWindow( pDisplay ), |
| &aRoot, &aParent, &pChildren, &nChildren ); |
| if( pChildren && nChildren ) |
| { |
| for( unsigned int i = 0; i < nChildren && ! ret; i++ ) |
| { |
| Atom nType = None; |
| int nFormat = 0; |
| unsigned long nItems = 0, nBytes = 0; |
| unsigned char* pProp = NULL; |
| XGetWindowProperty( pDisplay, |
| pChildren[i], |
| nNetWMNameAtom, |
| 0, 8, |
| False, |
| nUTFAtom, |
| &nType, |
| &nFormat, |
| &nItems, |
| &nBytes, |
| &pProp ); |
| if( pProp && nType == nUTFAtom ) |
| { |
| OString aWMName( (sal_Char*)pProp ); |
| if( aWMName.equalsIgnoreAsciiCase( "gnome-panel" ) ) |
| ret = true; |
| } |
| if( pProp ) |
| XFree( pProp ); |
| } |
| XFree( pChildren ); |
| } |
| } |
| } |
| |
| return ret; |
| } |
| |
| static bool bWasXError = false; |
| |
| static inline bool WasXError() |
| { |
| bool bRet = bWasXError; |
| bWasXError = false; |
| return bRet; |
| } |
| |
| extern "C" |
| { |
| static int autodect_error_handler( Display*, XErrorEvent* ) |
| { |
| bWasXError = true; |
| return 0; |
| } |
| |
| typedef int(* XErrorHandler)(Display*,XErrorEvent*); |
| } |
| |
| static int KDEVersion( Display* pDisplay ) |
| { |
| int nRet = 0; |
| |
| Atom nFullSession = XInternAtom( pDisplay, "KDE_FULL_SESSION", True ); |
| Atom nKDEVersion = XInternAtom( pDisplay, "KDE_SESSION_VERSION", True ); |
| |
| if( nFullSession ) |
| { |
| if( !nKDEVersion ) |
| return 3; |
| |
| Atom aRealType = None; |
| int nFormat = 8; |
| unsigned long nItems = 0; |
| unsigned long nBytesLeft = 0; |
| unsigned char* pProperty = NULL; |
| XGetWindowProperty( pDisplay, |
| DefaultRootWindow( pDisplay ), |
| nKDEVersion, |
| 0, 1, |
| False, |
| AnyPropertyType, |
| &aRealType, |
| &nFormat, |
| &nItems, |
| &nBytesLeft, |
| &pProperty ); |
| if( !WasXError() && nItems != 0 && pProperty ) |
| { |
| nRet = *reinterpret_cast< sal_Int32* >( pProperty ); |
| } |
| if( pProperty ) |
| { |
| XFree( pProperty ); |
| pProperty = NULL; |
| } |
| } |
| return nRet; |
| } |
| |
| static bool is_kde_desktop( Display* pDisplay ) |
| { |
| if ( NULL != getenv( "KDE_FULL_SESSION" ) ) |
| { |
| const char *pVer = getenv( "KDE_SESSION_VERSION" ); |
| if ( !pVer || pVer[0] == '0' ) |
| { |
| return true; // does not exist => KDE3 |
| } |
| |
| rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "3" ) ); |
| if ( aVer.equalsIgnoreAsciiCaseAscii( pVer ) ) |
| { |
| return true; |
| } |
| } |
| |
| if ( KDEVersion( pDisplay ) == 3 ) |
| return true; |
| |
| return false; |
| } |
| |
| static bool is_kde4_desktop( Display* pDisplay ) |
| { |
| if ( NULL != getenv( "KDE_FULL_SESSION" ) ) |
| { |
| rtl::OUString aVer( RTL_CONSTASCII_USTRINGPARAM( "4" ) ); |
| |
| const char *pVer = getenv( "KDE_SESSION_VERSION" ); |
| if ( pVer && aVer.equalsIgnoreAsciiCaseAscii( pVer ) ) |
| return true; |
| } |
| |
| if ( KDEVersion( pDisplay ) == 4 ) |
| return true; |
| |
| return false; |
| } |
| |
| static bool is_cde_desktop( Display* pDisplay ) |
| { |
| void* pLibrary = NULL; |
| |
| Atom nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True ); |
| if( nDtAtom && ( pLibrary = osl_loadAsciiModule( "file:///usr/dt/lib/libDtSvc.so", SAL_LOADMODULE_DEFAULT ) ) ) |
| { |
| osl_unloadModule( (oslModule)pLibrary ); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| |
| extern "C" |
| { |
| |
| DESKTOP_DETECTOR_PUBLIC rtl::OUString get_desktop_environment() |
| { |
| rtl::OUStringBuffer aRet( 8 ); |
| static const char *pOverride = getenv( "OOO_FORCE_DESKTOP" ); |
| |
| if ( pOverride && *pOverride ) |
| { |
| OString aOver( pOverride ); |
| |
| if ( aOver.equalsIgnoreAsciiCase( "cde" ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_CDE] ); |
| if ( aOver.equalsIgnoreAsciiCase( "kde4" ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_KDE4] ); |
| if ( aOver.equalsIgnoreAsciiCase( "gnome" ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_GNOME] ); |
| if ( aOver.equalsIgnoreAsciiCase( "kde" ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_KDE] ); |
| if ( aOver.equalsIgnoreAsciiCase( "none" ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] ); |
| } |
| |
| if( aRet.getLength() == 0 ) |
| { |
| // get display to connect to |
| const char* pDisplayStr = getenv( "DISPLAY" ); |
| int nParams = osl_getCommandArgCount(); |
| OUString aParam; |
| OString aBParm; |
| for( int i = 0; i < nParams; i++ ) |
| { |
| osl_getCommandArg( i, &aParam.pData ); |
| if( aParam.equalsAscii( "-headless" ) ) |
| { |
| pDisplayStr = NULL; |
| break; |
| } |
| if( i < nParams-1 && (aParam.equalsAscii( "-display" ) || aParam.equalsAscii( "--display" )) ) |
| { |
| osl_getCommandArg( i+1, &aParam.pData ); |
| aBParm = OUStringToOString( aParam, osl_getThreadTextEncoding() ); |
| pDisplayStr = aBParm.getStr(); |
| break; |
| } |
| } |
| |
| // no server at all |
| if( ! pDisplayStr || !*pDisplayStr ) |
| aRet.appendAscii( desktop_strings[DESKTOP_NONE] ); |
| else |
| { |
| /* #i92121# workaround deadlocks in the X11 implementation |
| */ |
| static const char* pNoXInitThreads = getenv( "SAL_NO_XINITTHREADS" ); |
| /* #i90094# |
| from now on we know that an X connection will be |
| established, so protect X against itself |
| */ |
| if( ! ( pNoXInitThreads && *pNoXInitThreads ) ) |
| XInitThreads(); |
| |
| Display* pDisplay = XOpenDisplay( pDisplayStr ); |
| if( pDisplay ) |
| { |
| XErrorHandler pOldHdl = XSetErrorHandler( autodect_error_handler ); |
| |
| if ( is_kde4_desktop( pDisplay ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_KDE4] ); |
| else if ( is_gnome_desktop( pDisplay ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_GNOME] ); |
| else if ( is_cde_desktop( pDisplay ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_CDE] ); |
| else if ( is_kde_desktop( pDisplay ) ) |
| aRet.appendAscii( desktop_strings[DESKTOP_KDE] ); |
| else |
| aRet.appendAscii( desktop_strings[DESKTOP_UNKNOWN] ); |
| |
| // set the default handler again |
| XSetErrorHandler( pOldHdl ); |
| |
| XCloseDisplay( pDisplay ); |
| } |
| } |
| } |
| |
| return aRet.makeStringAndClear(); |
| } |
| |
| } |