diff options
Diffstat (limited to 'vcl/unx/generic/app/wmadaptor.cxx')
-rw-r--r-- | vcl/unx/generic/app/wmadaptor.cxx | 2548 |
1 files changed, 2548 insertions, 0 deletions
diff --git a/vcl/unx/generic/app/wmadaptor.cxx b/vcl/unx/generic/app/wmadaptor.cxx new file mode 100644 index 000000000000..90b2e5426bdf --- /dev/null +++ b/vcl/unx/generic/app/wmadaptor.cxx @@ -0,0 +1,2548 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "sal/alloca.h" +#include "rtl/locale.h" + +#include "osl/thread.h" +#include "osl/process.h" + +#include "vcl/configsettings.hxx" + +#include "unx/wmadaptor.hxx" +#include "unx/saldisp.hxx" +#include "unx/saldata.hxx" +#include "unx/salframe.h" + +#include "salgdi.hxx" + +#include "tools/prex.h" +#include <X11/X.h> +#include <X11/Xatom.h> +#include <X11/Xresource.h> +#include "tools/postx.h" + +#if OSL_DEBUG_LEVEL > 1 +#include <stdio.h> +#endif + +namespace vcl_sal { + +class NetWMAdaptor : public WMAdaptor +{ + void setNetWMState( X11SalFrame* pFrame ) const; + void initAtoms(); + virtual bool isValid() const; +public: + NetWMAdaptor( SalDisplay* ); + virtual ~NetWMAdaptor(); + + virtual void setWMName( X11SalFrame* pFrame, const String& rWMName ) const; + virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const; + virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const; + virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame = NULL ) const; + virtual bool supportsICCCMPos() const; + virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const; + virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const; + virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const; + virtual void frameIsMapping( X11SalFrame* pFrame ) const; + virtual void setFrameStruts( X11SalFrame* pFrame, + int left, int right, int top, int bottom, + int left_start_y, int left_end_y, + int right_start_y, int right_end_y, + int top_start_x, int top_end_x, + int bottom_start_x, int bottom_end_x ) const; + virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const; +}; + +class GnomeWMAdaptor : public WMAdaptor +{ + bool m_bValid; + + void setGnomeWMState( X11SalFrame* pFrame ) const; + void initAtoms(); + virtual bool isValid() const; +public: + GnomeWMAdaptor( SalDisplay * ); + virtual ~GnomeWMAdaptor(); + + virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const; + virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const; + virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const; + virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const; +}; + +} + +using namespace vcl_sal; + +struct WMAdaptorProtocol +{ + const char* pProtocol; + int nProtocol; +}; + + +/* + * table must be sorted ascending in strings + * since it is use with bsearch + */ +static const WMAdaptorProtocol aProtocolTab[] = +{ + { "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", WMAdaptor::KDE_NET_WM_WINDOW_TYPE_OVERRIDE }, + { "_NET_CURRENT_DESKTOP", WMAdaptor::NET_CURRENT_DESKTOP }, + { "_NET_NUMBER_OF_DESKTOPS", WMAdaptor::NET_NUMBER_OF_DESKTOPS }, + { "_NET_WM_DESKTOP", WMAdaptor::NET_WM_DESKTOP }, + { "_NET_WM_ICON_NAME", WMAdaptor::NET_WM_ICON_NAME }, + { "_NET_WM_PING", WMAdaptor::NET_WM_PING }, + { "_NET_WM_STATE", WMAdaptor::NET_WM_STATE }, + { "_NET_WM_STATE_ABOVE", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP }, + { "_NET_WM_STATE_FULLSCREEN", WMAdaptor::NET_WM_STATE_FULLSCREEN }, + { "_NET_WM_STATE_MAXIMIZED_HORIZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ }, // common bug in e.g. older kwin and sawfish implementations + { "_NET_WM_STATE_MAXIMIZED_HORZ", WMAdaptor::NET_WM_STATE_MAXIMIZED_HORZ }, + { "_NET_WM_STATE_MAXIMIZED_VERT", WMAdaptor::NET_WM_STATE_MAXIMIZED_VERT }, + { "_NET_WM_STATE_MODAL", WMAdaptor::NET_WM_STATE_MODAL }, + { "_NET_WM_STATE_SHADED", WMAdaptor::NET_WM_STATE_SHADED }, + { "_NET_WM_STATE_SKIP_PAGER", WMAdaptor::NET_WM_STATE_SKIP_PAGER }, + { "_NET_WM_STATE_SKIP_TASKBAR", WMAdaptor::NET_WM_STATE_SKIP_TASKBAR }, + { "_NET_WM_STATE_STAYS_ON_TOP", WMAdaptor::NET_WM_STATE_STAYS_ON_TOP }, + { "_NET_WM_STATE_STICKY", WMAdaptor::NET_WM_STATE_STICKY }, + { "_NET_WM_STRUT", WMAdaptor::NET_WM_STRUT }, + { "_NET_WM_STRUT_PARTIAL", WMAdaptor::NET_WM_STRUT_PARTIAL }, + { "_NET_WM_WINDOW_TYPE", WMAdaptor::NET_WM_WINDOW_TYPE }, + { "_NET_WM_WINDOW_TYPE_DESKTOP", WMAdaptor::NET_WM_WINDOW_TYPE_DESKTOP }, + { "_NET_WM_WINDOW_TYPE_DIALOG", WMAdaptor::NET_WM_WINDOW_TYPE_DIALOG }, + { "_NET_WM_WINDOW_TYPE_DOCK", WMAdaptor::NET_WM_WINDOW_TYPE_DOCK }, + { "_NET_WM_WINDOW_TYPE_MENU", WMAdaptor::NET_WM_WINDOW_TYPE_MENU }, + { "_NET_WM_WINDOW_TYPE_NORMAL", WMAdaptor::NET_WM_WINDOW_TYPE_NORMAL }, + { "_NET_WM_WINDOW_TYPE_SPLASH", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH }, + { "_NET_WM_WINDOW_TYPE_SPLASHSCREEN", WMAdaptor::NET_WM_WINDOW_TYPE_SPLASH }, // bug in Metacity 2.4.1 + { "_NET_WM_WINDOW_TYPE_TOOLBAR", WMAdaptor::NET_WM_WINDOW_TYPE_TOOLBAR }, + { "_NET_WM_WINDOW_TYPE_UTILITY", WMAdaptor::NET_WM_WINDOW_TYPE_UTILITY }, + { "_NET_WORKAREA", WMAdaptor::NET_WORKAREA }, + { "_WIN_APP_STATE", WMAdaptor::WIN_APP_STATE }, + { "_WIN_CLIENT_LIST", WMAdaptor::WIN_CLIENT_LIST }, + { "_WIN_EXPANDED_SIZE", WMAdaptor::WIN_EXPANDED_SIZE }, + { "_WIN_HINTS", WMAdaptor::WIN_HINTS }, + { "_WIN_ICONS", WMAdaptor::WIN_ICONS }, + { "_WIN_LAYER", WMAdaptor::WIN_LAYER }, + { "_WIN_STATE", WMAdaptor::WIN_STATE }, + { "_WIN_WORKSPACE", WMAdaptor::WIN_WORKSPACE }, + { "_WIN_WORKSPACE_COUNT", WMAdaptor::WIN_WORKSPACE_COUNT } +}; + +/* + * table containing atoms to get anyway + */ + +static const WMAdaptorProtocol aAtomTab[] = +{ + { "WM_STATE", WMAdaptor::WM_STATE }, + { "_MOTIF_WM_HINTS", WMAdaptor::MOTIF_WM_HINTS }, + { "WM_PROTOCOLS", WMAdaptor::WM_PROTOCOLS }, + { "WM_DELETE_WINDOW", WMAdaptor::WM_DELETE_WINDOW }, + { "WM_TAKE_FOCUS", WMAdaptor::WM_TAKE_FOCUS }, + { "WM_SAVE_YOURSELF", WMAdaptor::WM_SAVE_YOURSELF }, + { "WM_COMMAND", WMAdaptor::WM_COMMAND }, + { "WM_CLIENT_LEADER", WMAdaptor::WM_CLIENT_LEADER }, + { "WM_LOCALE_NAME", WMAdaptor::WM_LOCALE_NAME }, + { "WM_TRANSIENT_FOR", WMAdaptor::WM_TRANSIENT_FOR }, + { "SAL_QUITEVENT", WMAdaptor::SAL_QUITEVENT }, + { "SAL_USEREVENT", WMAdaptor::SAL_USEREVENT }, + { "SAL_EXTTEXTEVENT", WMAdaptor::SAL_EXTTEXTEVENT }, + { "SAL_GETTIMEEVENT", WMAdaptor::SAL_GETTIMEEVENT }, + { "VCL_SYSTEM_SETTINGS", WMAdaptor::VCL_SYSTEM_SETTINGS }, + { "DTWM_IS_RUNNING", WMAdaptor::DTWM_IS_RUNNING }, + { "_XSETTINGS_SETTINGS", WMAdaptor::XSETTINGS }, + { "_XEMBED", WMAdaptor::XEMBED }, + { "_XEMBED_INFO", WMAdaptor::XEMBED_INFO }, + { "_NET_WM_USER_TIME", WMAdaptor::NET_WM_USER_TIME }, + { "_NET_WM_PID", WMAdaptor::NET_WM_PID } +}; + +extern "C" { +static int compareProtocol( const void* pLeft, const void* pRight ) +{ + return strcmp( ((const WMAdaptorProtocol*)pLeft)->pProtocol, ((const WMAdaptorProtocol*)pRight)->pProtocol ); +} +} + +WMAdaptor* WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay ) +{ + WMAdaptor* pAdaptor = NULL; + + // try a NetWM + pAdaptor = new NetWMAdaptor( pSalDisplay ); + if( ! pAdaptor->isValid() ) + delete pAdaptor, pAdaptor = NULL; +#if OSL_DEBUG_LEVEL > 1 + else + fprintf( stderr, "WM supports extended WM hints\n" ); +#endif + + // try a GnomeWM + if( ! pAdaptor ) + { + pAdaptor = new GnomeWMAdaptor( pSalDisplay ); + if( ! pAdaptor->isValid() ) + delete pAdaptor, pAdaptor = NULL; +#if OSL_DEBUG_LEVEL > 1 + else + fprintf( stderr, "WM supports GNOME WM hints\n" ); +#endif + } + + if( ! pAdaptor ) + pAdaptor = new WMAdaptor( pSalDisplay ); + +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "Window Manager's name is \"%s\"\n", + ByteString( pAdaptor->getWindowManagerName(), RTL_TEXTENCODING_ISO_8859_1 ).GetBuffer() ); +#endif + return pAdaptor; +} + + +/* + * WMAdaptor constructor + */ + +WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) : + m_pSalDisplay( pDisplay ), + m_bTransientBehaviour( true ), + m_bEnableAlwaysOnTopWorks( false ), + m_bLegacyPartialFullscreen( false ), + m_nWinGravity( StaticGravity ), + m_nInitWinGravity( StaticGravity ), + m_bWMshouldSwitchWorkspace( true ), + m_bWMshouldSwitchWorkspaceInit( false ) +{ + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + + // default desktops + m_nDesktops = 1; + m_aWMWorkAreas = ::std::vector< Rectangle > + ( 1, Rectangle( Point(), m_pSalDisplay->GetScreenSize( m_pSalDisplay->GetDefaultScreenNumber() ) ) ); + m_bEqualWorkAreas = true; + + memset( m_aWMAtoms, 0, sizeof( m_aWMAtoms ) ); + m_pDisplay = m_pSalDisplay->GetDisplay(); + + initAtoms(); + getNetWmName(); // try to discover e.g. Sawfish + + // check for dtwm running + if( m_aWMAtoms[ DTWM_IS_RUNNING ] ) + { + if ( (XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ DTWM_IS_RUNNING ], + 0, 1, + False, + XA_INTEGER, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty) == 0 + && nItems) + || (XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ DTWM_IS_RUNNING ], + 0, 1, + False, + m_aWMAtoms[ DTWM_IS_RUNNING ], + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty) == 0 + && nItems)) + { + if (*pProperty) + { + m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("Dtwm")); + m_bTransientBehaviour = false; + m_nWinGravity = CenterGravity; + } + XFree (pProperty); + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + if( m_aWMName.Len() == 0 ) + { + // check for window maker - needs different gravity + Atom aWMakerRunning = XInternAtom( m_pDisplay, "_WINDOWMAKER_WM_PROTOCOLS", True ); + if( aWMakerRunning != None && + XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + aWMakerRunning, + 0, 32, + False, + XA_ATOM, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 ) + { + if( aRealType == XA_ATOM ) + m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Windowmaker" ) ); + XFree( pProperty ); + m_nInitWinGravity = NorthWestGravity; + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + if( m_aWMName.Len() == 0 ) + { + if( XInternAtom( m_pDisplay, "_OL_WIN_ATTR", True ) ) + { + m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "Olwm" ) ); + m_nInitWinGravity = NorthWestGravity; + } + } + if( m_aWMName.Len() == 0 ) + { + // check for ReflectionX wm (as it needs a workaround in Windows mode + Atom aRwmRunning = XInternAtom( m_pDisplay, "RWM_RUNNING", True ); + if( aRwmRunning != None && + XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + aRwmRunning, + 0, 32, + False, + aRwmRunning, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 ) + { + if( aRealType == aRwmRunning ) + m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("ReflectionX" ) ); + XFree( pProperty ); + } + else if( (aRwmRunning = XInternAtom( m_pDisplay, "_WRQ_WM_RUNNING", True )) != None && + XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + aRwmRunning, + 0, 32, + False, + XA_STRING, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 ) + { + if( aRealType == XA_STRING ) + m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM( "ReflectionX Windows" ) ); + XFree( pProperty ); + } + } + if( m_aWMName.Len() == 0 ) + { + Atom aTTAPlatform = XInternAtom( m_pDisplay, "TTA_CLIENT_PLATFORM", True ); + if( aTTAPlatform != None && + XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + aTTAPlatform, + 0, 32, + False, + XA_STRING, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 ) + { + if( aRealType == XA_STRING ) + { + m_aWMName = String( RTL_CONSTASCII_USTRINGPARAM("Tarantella" ) ); + // #i62319# pretend that AlwaysOnTop works since + // the alwaysontop workaround in salframe.cxx results + // in a raise/lower loop on a Windows tarantella client + // FIXME: this property contains an identification string that + // in theory should be good enough to recognize running on a + // Windows client; however this string does not seem to be + // documented as well as the property itself. + m_bEnableAlwaysOnTopWorks = true; + } + XFree( pProperty ); + } + } +} + +/* + * WMAdaptor destructor + */ + +WMAdaptor::~WMAdaptor() +{ +} + +/* + * NetWMAdaptor constructor + */ + +NetWMAdaptor::NetWMAdaptor( SalDisplay* pSalDisplay ) : + WMAdaptor( pSalDisplay ) +{ + // currently all _NET WMs do transient like expected + m_bTransientBehaviour = true; + + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + bool bNetWM = false; + + initAtoms(); + + // check for NetWM + bNetWM = getNetWmName(); + if( bNetWM + && XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_SUPPORTED ], + 0, 0, + False, + XA_ATOM, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_ATOM + && nFormat == 32 + ) + { + if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + // collect supported protocols + if( XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_SUPPORTED ], + 0, nBytesLeft/4, + False, + XA_ATOM, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && nItems + ) + { + Atom* pAtoms = (Atom*)pProperty; + char** pAtomNames = (char**)alloca( sizeof(char*)*nItems ); + if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "supported protocols:\n" ); +#endif + for( unsigned int i = 0; i < nItems; i++ ) + { + // #i80971# protect against invalid atoms + if( pAtomNames[i] == NULL ) + continue; + + int nProtocol = -1; + WMAdaptorProtocol aSearch; + aSearch.pProtocol = pAtomNames[i]; + WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*) + bsearch( &aSearch, + aProtocolTab, + sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ), + sizeof( struct WMAdaptorProtocol ), + compareProtocol ); + if( pMatch ) + { + nProtocol = pMatch->nProtocol; + m_aWMAtoms[ nProtocol ] = pAtoms[ i ]; + if( pMatch->nProtocol == NET_WM_STATE_STAYS_ON_TOP ) + m_bEnableAlwaysOnTopWorks = true; + } +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" ); +#endif + + XFree( pAtomNames[i] ); + } + } + XFree( pProperty ); + pProperty = NULL; + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + + // get number of desktops + if( m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ] + && XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && pProperty + ) + { + m_nDesktops = *(long*)pProperty; + XFree( pProperty ); + pProperty = NULL; + // get work areas + if( m_aWMAtoms[ NET_WORKAREA ] + && XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_WORKAREA ], + 0, 4*m_nDesktops, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty + ) == 0 + && nItems == 4*(unsigned)m_nDesktops + ) + { + m_aWMWorkAreas = ::std::vector< Rectangle > ( m_nDesktops ); + long* pValues = (long*)pProperty; + for( int i = 0; i < m_nDesktops; i++ ) + { + Point aPoint( pValues[4*i], + pValues[4*i+1] ); + Size aSize( pValues[4*i+2], + pValues[4*i+3] ); + Rectangle aWorkArea( aPoint, aSize ); + m_aWMWorkAreas[i] = aWorkArea; + if( aWorkArea != m_aWMWorkAreas[0] ) + m_bEqualWorkAreas = false; +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "workarea %d: %ldx%ld+%ld+%ld\n", + i, + m_aWMWorkAreas[i].GetWidth(), + m_aWMWorkAreas[i].GetHeight(), + m_aWMWorkAreas[i].Left(), + m_aWMWorkAreas[i].Top() ); +#endif + } + XFree( pProperty ); + } + else + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "%ld workareas for %d desktops !\n", nItems/4, m_nDesktops ); +#endif + if( pProperty ) + { + XFree(pProperty); + pProperty = NULL; + } + } + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } +} + +/* + * NetWMAdaptor destructor + */ +NetWMAdaptor::~NetWMAdaptor() +{ +} + +/* + * GnomeWMAdaptor constructor + */ + +GnomeWMAdaptor::GnomeWMAdaptor( SalDisplay* pSalDisplay ) : + WMAdaptor( pSalDisplay ), + m_bValid( false ) +{ + // currently all Gnome WMs do transient like expected + m_bTransientBehaviour = true; + + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + + initAtoms(); + + // check for GnomeWM + if( m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ WIN_PROTOCOLS ] ) + { + XLIB_Window aWMChild = None; + if( XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_CARDINAL + && nFormat == 32 + && nItems != 0 + ) + { + aWMChild = *(XLIB_Window*)pProperty; + XFree( pProperty ); + pProperty = NULL; + XLIB_Window aCheckWindow = None; + m_pSalDisplay->GetXLib()->PushXErrorLevel( true ); + if( XGetWindowProperty( m_pDisplay, + aWMChild, + m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_CARDINAL + && nFormat == 32 + && nItems != 0 + && ! m_pSalDisplay->GetXLib()->HasXErrorOccured() + ) + { + aCheckWindow = *(XLIB_Window*)pProperty; + XFree( pProperty ); + pProperty = NULL; + if( aCheckWindow == aWMChild ) + { + m_bValid = true; + /* + * get name of WM + * this is NOT part of the GNOME WM hints, but e.g. Sawfish + * already supports this part of the extended WM hints + */ + m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False ); + getNetWmName(); + } + } + m_pSalDisplay->GetXLib()->PopXErrorLevel(); + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + if( m_bValid + && XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ WIN_PROTOCOLS ], + 0, 0, + False, + XA_ATOM, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_ATOM + && nFormat == 32 + ) + { + if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + // collect supported protocols + if( XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ WIN_PROTOCOLS ], + 0, nBytesLeft/4, + False, + XA_ATOM, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && pProperty + ) + { + Atom* pAtoms = (Atom*)pProperty; + char** pAtomNames = (char**)alloca( sizeof(char*)*nItems ); + if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) ) + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "supported protocols:\n" ); +#endif + for( unsigned int i = 0; i < nItems; i++ ) + { + // #i80971# protect against invalid atoms + if( pAtomNames[i] == NULL ) + continue; + + int nProtocol = -1; + WMAdaptorProtocol aSearch; + aSearch.pProtocol = pAtomNames[i]; + WMAdaptorProtocol* pMatch = (WMAdaptorProtocol*) + bsearch( &aSearch, + aProtocolTab, + sizeof( aProtocolTab )/sizeof( aProtocolTab[0] ), + sizeof( struct WMAdaptorProtocol ), + compareProtocol ); + if( pMatch ) + { + nProtocol = pMatch->nProtocol; + m_aWMAtoms[ nProtocol ] = pAtoms[ i ]; + if( pMatch->nProtocol == WIN_LAYER ) + m_bEnableAlwaysOnTopWorks = true; + } + if( strncmp( "_ICEWM_TRAY", pAtomNames[i], 11 ) == 0 ) + { + m_aWMName = String(RTL_CONSTASCII_USTRINGPARAM("IceWM" )); + m_nWinGravity = NorthWestGravity; + m_nInitWinGravity = NorthWestGravity; + } +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, " %s%s\n", pAtomNames[i], nProtocol != -1 ? "" : " (unsupported)" ); +#endif + + XFree( pAtomNames[i] ); + } + } + XFree( pProperty ); + pProperty = NULL; + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + + // get number of desktops + if( m_aWMAtoms[ WIN_WORKSPACE_COUNT ] + && XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ WIN_WORKSPACE_COUNT ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && pProperty + ) + { + m_nDesktops = *(long*)pProperty; + XFree( pProperty ); + pProperty = NULL; + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } +} + +/* + * GnomeWMAdaptor destructor + */ +GnomeWMAdaptor::~GnomeWMAdaptor() +{ +} + +/* + * getNetWmName() + */ +bool WMAdaptor::getNetWmName() +{ + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + bool bNetWM = false; + + if( m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ NET_WM_NAME ] ) + { + XLIB_Window aWMChild = None; + if( XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ], + 0, 1, + False, + XA_WINDOW, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_WINDOW + && nFormat == 32 + && nItems != 0 + ) + { + aWMChild = *(XLIB_Window*)pProperty; + XFree( pProperty ); + pProperty = NULL; + XLIB_Window aCheckWindow = None; + m_pSalDisplay->GetXLib()->PushXErrorLevel( true ); + if( XGetWindowProperty( m_pDisplay, + aWMChild, + m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ], + 0, 1, + False, + XA_WINDOW, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && aRealType == XA_WINDOW + && nFormat == 32 + && nItems != 0 + && ! m_pSalDisplay->GetXLib()->HasXErrorOccured() + ) + { + aCheckWindow = *(XLIB_Window*)pProperty; + XFree( pProperty ); + pProperty = NULL; + if( aCheckWindow == aWMChild ) + { + bNetWM = true; + // get name of WM + m_aWMAtoms[ UTF8_STRING ] = XInternAtom( m_pDisplay, "UTF8_STRING", False ); + if( XGetWindowProperty( m_pDisplay, + aWMChild, + m_aWMAtoms[ NET_WM_NAME ], + 0, 256, + False, + AnyPropertyType, /* m_aWMAtoms[ UTF8_STRING ],*/ + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && nItems != 0 + ) + { + if (aRealType == m_aWMAtoms[ UTF8_STRING ]) + { + m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 ); + } + else + if (aRealType == XA_STRING) + { + m_aWMName = String( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_ISO_8859_1 ); + } + + XFree( pProperty ); + pProperty = NULL; + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + // if this is metacity, check for version to enable a legacy workaround + if( m_aWMName.EqualsAscii( "Metacity" ) ) + { + int nVersionMajor = 0, nVersionMinor = 0; + Atom nVersionAtom = XInternAtom( m_pDisplay, "_METACITY_VERSION", True ); + if( nVersionAtom ) + { + if( XGetWindowProperty( m_pDisplay, + aWMChild, + nVersionAtom, + 0, 256, + False, + m_aWMAtoms[ UTF8_STRING ], + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && nItems != 0 + ) + { + String aMetaVersion( (sal_Char*)pProperty, nItems, RTL_TEXTENCODING_UTF8 ); + nVersionMajor = aMetaVersion.GetToken( 0, '.' ).ToInt32(); + nVersionMinor = aMetaVersion.GetToken( 1, '.' ).ToInt32(); + } + if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + if( nVersionMajor < 2 || (nVersionMajor == 2 && nVersionMinor < 12) ) + m_bLegacyPartialFullscreen = true; + } + } + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + m_pSalDisplay->GetXLib()->PopXErrorLevel(); + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + return bNetWM; +} + +bool WMAdaptor::getWMshouldSwitchWorkspace() const +{ + if( ! m_bWMshouldSwitchWorkspaceInit ) + { + WMAdaptor * pWMA = const_cast<WMAdaptor*>(this); + + pWMA->m_bWMshouldSwitchWorkspace = true; + vcl::SettingsConfigItem* pItem = vcl::SettingsConfigItem::get(); + rtl::OUString aSetting( pItem->getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "WM" ) ), + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ShouldSwitchWorkspace" ) ) ) ); + if( aSetting.getLength() == 0 ) + { + if( m_aWMName.EqualsAscii( "awesome" ) ) + { + pWMA->m_bWMshouldSwitchWorkspace = false; + } + } + else + pWMA->m_bWMshouldSwitchWorkspace = aSetting.toBoolean(); + pWMA->m_bWMshouldSwitchWorkspaceInit = true; + } + return m_bWMshouldSwitchWorkspace; +} + +/* + * WMAdaptor::isValid() + */ +bool WMAdaptor::isValid() const +{ + return true; +} + +/* + * NetWMAdaptor::isValid() + */ +bool NetWMAdaptor::isValid() const +{ + // some necessary sanity checks; there are WMs out there + // which implement some of the WM hints spec without + // real functionality + return + m_aWMAtoms[ NET_SUPPORTED ] + && m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] + && m_aWMAtoms[ NET_WM_NAME ] + && m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ] + && m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ] + ; +} + +/* + * GnomeWMAdaptor::isValid() + */ +bool GnomeWMAdaptor::isValid() const +{ + return m_bValid; +} + +/* + * WMAdaptor::initAtoms + */ + +void WMAdaptor::initAtoms() +{ + // get basic atoms + for( unsigned int i = 0; i < sizeof( aAtomTab )/sizeof( aAtomTab[0] ); i++ ) + m_aWMAtoms[ aAtomTab[i].nProtocol ] = XInternAtom( m_pDisplay, aAtomTab[i].pProtocol, False ); + m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_NET_SUPPORTING_WM_CHECK", True ); + m_aWMAtoms[ NET_WM_NAME ] = XInternAtom( m_pDisplay, "_NET_WM_NAME", True ); +} + +/* + * NetWMAdaptor::initAtoms + */ + +void NetWMAdaptor::initAtoms() +{ + WMAdaptor::initAtoms(); + + m_aWMAtoms[ NET_SUPPORTED ] = XInternAtom( m_pDisplay, "_NET_SUPPORTED", True ); +} + +/* + * GnomeWMAdaptor::initAtoms + */ + +void GnomeWMAdaptor::initAtoms() +{ + WMAdaptor::initAtoms(); + + m_aWMAtoms[ WIN_PROTOCOLS ] = XInternAtom( m_pDisplay, "_WIN_PROTOCOLS", True ); + m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] = XInternAtom( m_pDisplay, "_WIN_SUPPORTING_WM_CHECK", True ); +} + +/* + * WMAdaptor::setWMName + * sets WM_NAME + * WM_ICON_NAME + */ + +void WMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const +{ + ByteString aTitle( rWMName, osl_getThreadTextEncoding() ); + + if( ! rWMName.Len() && m_aWMName.EqualsAscii( "Dtwm" ) ) + aTitle = " "; + + ::rtl::OString aWMLocale; + rtl_Locale* pLocale = NULL; + osl_getProcessLocale( &pLocale ); + if( pLocale ) + { + ::rtl::OUString aLocaleString( pLocale->Language ); + ::rtl::OUString aCountry( pLocale->Country ); + ::rtl::OUString aVariant( pLocale->Variant ); + + if( aCountry.getLength() ) + { + aLocaleString += ::rtl::OUString::createFromAscii( "_" ); + aLocaleString += aCountry; + } + if( aVariant.getLength() ) + aLocaleString += aVariant; + aWMLocale = ::rtl::OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 ); + } + else + { + static const char* pLang = getenv( "LANG" ); + aWMLocale = pLang ? pLang : "C"; + } + + static bool bTrustXmb = true; + #ifdef SOLARIS + /* #i64273# there are some weird cases when using IIIMP on Solaris + * where for unknown reasons XmbTextListToTextProperty results in + * garbage. Test one string once to ensure safety. + * + * FIXME: This must be a bug in xiiimp.so.2 somewhere. However + * it was not possible to recreate this in a small sample program. + * This reeks of memory corruption somehow. + */ + static bool bOnce = true; + if( bOnce ) + { + bOnce = false; + XTextProperty aTestProp = { NULL, None, 0, 0 }; + const char *pText = "trustme"; + XmbTextListToTextProperty( m_pDisplay, + &const_cast<char*>(pText), + 1, + XStdICCTextStyle, + &aTestProp ); + bTrustXmb = (aTestProp.nitems == 7) && + (aTestProp.value != NULL ) && + (strncmp( (char*)aTestProp.value, pText, 7 ) == 0) && + (aTestProp.encoding == XA_STRING); + if( aTestProp.value ) + XFree( aTestProp.value ); + #if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "%s\n", + bTrustXmb ? + "XmbTextListToTextProperty seems to work" : + "XmbTextListToTextProperty does not seem to work" ); + #endif + } + #endif + + char* pT = const_cast<char*>(aTitle.GetBuffer()); + XTextProperty aProp = { NULL, None, 0, 0 }; + if( bTrustXmb ) + { + XmbTextListToTextProperty( m_pDisplay, + &pT, + 1, + XStdICCTextStyle, + &aProp ); + } + + unsigned char* pData = aProp.nitems ? aProp.value : (unsigned char*)aTitle.GetBuffer(); + Atom nType = aProp.nitems ? aProp.encoding : XA_STRING; + int nFormat = aProp.nitems ? aProp.format : 8; + int nBytes = aProp.nitems ? aProp.nitems : aTitle.Len(); + const SystemEnvData* pEnv = pFrame->GetSystemData(); + XChangeProperty( m_pDisplay, + (XLIB_Window)pEnv->aShellWindow, + XA_WM_NAME, + nType, + nFormat, + PropModeReplace, + pData, + nBytes ); + XChangeProperty( m_pDisplay, + (XLIB_Window)pEnv->aShellWindow, + XA_WM_ICON_NAME, + nType, + nFormat, + PropModeReplace, + pData, + nBytes ); + XChangeProperty( m_pDisplay, + (XLIB_Window)pEnv->aShellWindow, + m_aWMAtoms[ WM_LOCALE_NAME ], + XA_STRING, + 8, + PropModeReplace, + (unsigned char*)aWMLocale.getStr(), + aWMLocale.getLength() ); + if (aProp.value != NULL) + XFree( aProp.value ); +} + +/* + * NetWMAdaptor::setWMName + * sets WM_NAME + * _NET_WM_NAME + * WM_ICON_NAME + * _NET_WM_ICON_NAME + */ +void NetWMAdaptor::setWMName( X11SalFrame* pFrame, const String& rWMName ) const +{ + WMAdaptor::setWMName( pFrame, rWMName ); + + ByteString aTitle( rWMName, RTL_TEXTENCODING_UTF8 ); + const SystemEnvData* pEnv = pFrame->GetSystemData(); + if( m_aWMAtoms[ NET_WM_NAME ] ) + XChangeProperty( m_pDisplay, + (XLIB_Window)pEnv->aShellWindow, + m_aWMAtoms[ NET_WM_NAME ], + m_aWMAtoms[ UTF8_STRING ], + 8, + PropModeReplace, + (unsigned char*)aTitle.GetBuffer(), + aTitle.Len()+1 ); + if( m_aWMAtoms[ NET_WM_ICON_NAME ] ) + XChangeProperty( m_pDisplay, + (XLIB_Window)pEnv->aShellWindow, + m_aWMAtoms[ NET_WM_ICON_NAME ], + m_aWMAtoms[ UTF8_STRING ], + 8, + PropModeReplace, + (unsigned char*)aTitle.GetBuffer(), + aTitle.Len()+1 ); + // The +1 copies the terminating null byte. Although + // the spec says, this should not be necessary + // at least the kwin implementation seems to depend + // on the null byte +} + +/* + * NetWMAdaptor::setNetWMState + * sets _NET_WM_STATE + */ +void NetWMAdaptor::setNetWMState( X11SalFrame* pFrame ) const +{ + if( m_aWMAtoms[ NET_WM_STATE ] ) + { + Atom aStateAtoms[ 10 ]; + int nStateAtoms = 0; + + // set NET_WM_STATE_MODAL + if( m_aWMAtoms[ NET_WM_STATE_MODAL ] + && pFrame->meWindowType == windowType_ModalDialogue ) + { + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MODAL ]; + /* + * #90998# NET_WM_STATE_SKIP_TASKBAR set on a frame will + * cause kwin not to give it the focus on map request + * this seems to be a bug in kwin + * aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ]; + */ + } + if( pFrame->mbMaximizedVert + && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ]; + if( pFrame->mbMaximizedHorz + && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ]; + if( pFrame->bAlwaysOnTop_ && m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ]; + if( pFrame->mbShaded && m_aWMAtoms[ NET_WM_STATE_SHADED ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SHADED ]; + if( pFrame->mbFullScreen && m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ]; + if( pFrame->meWindowType == windowType_Utility && m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ] ) + aStateAtoms[ nStateAtoms++ ] = m_aWMAtoms[ NET_WM_STATE_SKIP_TASKBAR ]; + + if( nStateAtoms ) + { + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ NET_WM_STATE ], + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)aStateAtoms, + nStateAtoms + ); + } + else + XDeleteProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ NET_WM_STATE ] ); + if( pFrame->mbMaximizedHorz + && pFrame->mbMaximizedVert + && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) ) + { + /* + * for maximizing use NorthWestGravity (including decoration) + */ + XSizeHints hints; + long supplied; + bool bHint = false; + if( XGetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints, + &supplied ) ) + { + bHint = true; + hints.flags |= PWinGravity; + hints.win_gravity = NorthWestGravity; + XSetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints ); + XSync( m_pDisplay, False ); + } + + // SetPosSize necessary to set width/height, min/max w/h + sal_Int32 nCurrent = 0; + /* + * get current desktop here if work areas have different size + * (does this happen on any platform ?) + */ + if( ! m_bEqualWorkAreas ) + { + nCurrent = getCurrentWorkArea(); + if( nCurrent < 0 ) + nCurrent = 0; + } + Rectangle aPosSize = m_aWMWorkAreas[nCurrent]; + const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); + aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration, + aPosSize.Top() + rGeom.nTopDecoration ), + Size( aPosSize.GetWidth() + - rGeom.nLeftDecoration + - rGeom.nRightDecoration, + aPosSize.GetHeight() + - rGeom.nTopDecoration + - rGeom.nBottomDecoration ) + ); + pFrame->SetPosSize( aPosSize ); + + /* + * reset gravity hint to static gravity + * (this should not move window according to ICCCM) + */ + if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN ) + { + hints.win_gravity = StaticGravity; + XSetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints ); + } + } + } +} + +/* + * GnomeWMAdaptor::setNetWMState + * sets _WIN_STATE + */ +void GnomeWMAdaptor::setGnomeWMState( X11SalFrame* pFrame ) const +{ + if( m_aWMAtoms[ WIN_STATE ] ) + { + sal_uInt32 nWinWMState = 0; + + if( pFrame->mbMaximizedVert ) + nWinWMState |= 1 << 2; + if( pFrame->mbMaximizedHorz ) + nWinWMState |= 1 << 3; + if( pFrame->mbShaded ) + nWinWMState |= 1 << 5; + + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ WIN_STATE ], + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&nWinWMState, + 1 + ); + if( pFrame->mbMaximizedHorz + && pFrame->mbMaximizedVert + && ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_SIZEABLE ) ) + { + /* + * for maximizing use NorthWestGravity (including decoration) + */ + XSizeHints hints; + long supplied; + bool bHint = false; + if( XGetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints, + &supplied ) ) + { + bHint = true; + hints.flags |= PWinGravity; + hints.win_gravity = NorthWestGravity; + XSetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints ); + XSync( m_pDisplay, False ); + } + + // SetPosSize necessary to set width/height, min/max w/h + sal_Int32 nCurrent = 0; + /* + * get current desktop here if work areas have different size + * (does this happen on any platform ?) + */ + if( ! m_bEqualWorkAreas ) + { + nCurrent = getCurrentWorkArea(); + if( nCurrent < 0 ) + nCurrent = 0; + } + Rectangle aPosSize = m_aWMWorkAreas[nCurrent]; + const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); + aPosSize = Rectangle( Point( aPosSize.Left() + rGeom.nLeftDecoration, + aPosSize.Top() + rGeom.nTopDecoration ), + Size( aPosSize.GetWidth() + - rGeom.nLeftDecoration + - rGeom.nRightDecoration, + aPosSize.GetHeight() + - rGeom.nTopDecoration + - rGeom.nBottomDecoration ) + ); + pFrame->SetPosSize( aPosSize ); + + /* + * reset gravity hint to static gravity + * (this should not move window according to ICCCM) + */ + if( bHint && pFrame->nShowState_ != SHOWSTATE_UNKNOWN ) + { + hints.win_gravity = StaticGravity; + XSetWMNormalHints( m_pDisplay, + pFrame->GetShellWindow(), + &hints ); + } + } + } +} + +/* + * WMAdaptor::setFrameDecoration + * sets _MOTIF_WM_HINTS + * WM_TRANSIENT_FOR + */ + +void WMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const +{ + pFrame->meWindowType = eType; + pFrame->mnDecorationFlags = nDecorationFlags; + + if( ! pFrame->mbFullScreen ) + { + // set mwm hints + struct _mwmhints { + unsigned long flags, func, deco; + long input_mode; + unsigned long status; + } aHint; + + aHint.flags = 15; /* flags for functions, decoration, input mode and status */ + aHint.deco = 0; + aHint.func = 1L << 2; + aHint.status = 0; + aHint.input_mode = 0; + + // evaluate decoration flags + if( nDecorationFlags & decoration_All ) + aHint.deco = 1, aHint.func = 1; + else + { + if( nDecorationFlags & decoration_Title ) + aHint.deco |= 1L << 3; + if( nDecorationFlags & decoration_Border ) + aHint.deco |= 1L << 1; + if( nDecorationFlags & decoration_Resize ) + aHint.deco |= 1L << 2, aHint.func |= 1L << 1; + if( nDecorationFlags & decoration_MinimizeBtn ) + aHint.deco |= 1L << 5, aHint.func |= 1L << 3; + if( nDecorationFlags & decoration_MaximizeBtn ) + aHint.deco |= 1L << 6, aHint.func |= 1L << 4; + if( nDecorationFlags & decoration_CloseBtn ) + aHint.deco |= 1L << 4, aHint.func |= 1L << 5; + } + // evaluate window type + switch( eType ) + { + case windowType_ModalDialogue: + aHint.input_mode = 1; + break; + default: + break; + } + + // set the hint + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ MOTIF_WM_HINTS ], + m_aWMAtoms[ MOTIF_WM_HINTS ], + 32, + PropModeReplace, + (unsigned char*)&aHint, + 5 ); + } + + // set transientFor hint + /* #91030# dtwm will not map a dialogue if the transient + * window is iconified. This is deemed undesireable because + * message boxes do not get mapped, so use the root as transient + * instead. + */ + if( pReferenceFrame ) + { + XSetTransientForHint( m_pDisplay, + pFrame->GetShellWindow(), + pReferenceFrame->bMapped_ ? + pReferenceFrame->GetShellWindow() : + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ) + ); + if( ! pReferenceFrame->bMapped_ ) + pFrame->mbTransientForRoot = true; + } + // #110333# in case no one ever sets a title prevent + // the Dtwm taking the class instead + if( m_aWMName.EqualsAscii( "Dtwm" ) ) + setWMName( pFrame, String() ); +} + +/* + * NetWMAdaptor::setFrameDecoration + * sets _MOTIF_WM_HINTS + * _NET_WM_WINDOW_TYPE + * _NET_WM_STATE + * WM_TRANSIENT_FOR + */ + +void NetWMAdaptor::setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pReferenceFrame ) const +{ + WMAdaptor::setFrameTypeAndDecoration( pFrame, eType, nDecorationFlags, pReferenceFrame ); + + setNetWMState( pFrame ); + + // set NET_WM_WINDOW_TYPE + if( m_aWMAtoms[ NET_WM_WINDOW_TYPE ] ) + { + Atom aWindowTypes[4]; + int nWindowTypes = 0; + switch( eType ) + { + case windowType_Utility: + aWindowTypes[nWindowTypes++] = + m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] ? + m_aWMAtoms[ NET_WM_WINDOW_TYPE_UTILITY ] : + m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]; + break; + case windowType_ModelessDialogue: + case windowType_ModalDialogue: + aWindowTypes[nWindowTypes++] = + m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]; + break; + case windowType_Splash: + aWindowTypes[nWindowTypes++] = + m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] ? + m_aWMAtoms[ NET_WM_WINDOW_TYPE_SPLASH ] : + m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ]; + break; + case windowType_Toolbar: + if( m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ] ) + aWindowTypes[nWindowTypes++] = m_aWMAtoms[ KDE_NET_WM_WINDOW_TYPE_OVERRIDE ]; + aWindowTypes[nWindowTypes++] = + m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] ? + m_aWMAtoms[ NET_WM_WINDOW_TYPE_TOOLBAR ] : + m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL]; + break; + case windowType_Dock: + aWindowTypes[nWindowTypes++] = + m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] ? + m_aWMAtoms[ NET_WM_WINDOW_TYPE_DOCK ] : + m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL]; + break; + default: + aWindowTypes[nWindowTypes++] = m_aWMAtoms[ NET_WM_WINDOW_TYPE_NORMAL ]; + break; + } + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ NET_WM_WINDOW_TYPE ], + XA_ATOM, + 32, + PropModeReplace, + (unsigned char*)aWindowTypes, + nWindowTypes ); + } + if( ( eType == windowType_ModalDialogue || + eType == windowType_ModelessDialogue ) + && ! pReferenceFrame ) + { + XSetTransientForHint( m_pDisplay, + pFrame->GetShellWindow(), + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ) ); + pFrame->mbTransientForRoot = true; + } +} + +/* + * WMAdaptor::maximizeFrame + */ + +void WMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const +{ + pFrame->mbMaximizedVert = bVertical; + pFrame->mbMaximizedHorz = bHorizontal; + + const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); + + // discard pending configure notifies for this frame + XSync( m_pDisplay, False ); + XEvent aDiscard; + while( XCheckTypedWindowEvent( m_pDisplay, + pFrame->GetShellWindow(), + ConfigureNotify, + &aDiscard ) ) + ; + while( XCheckTypedWindowEvent( m_pDisplay, + pFrame->GetWindow(), + ConfigureNotify, + &aDiscard ) ) + ; + + if( bHorizontal || bVertical ) + { + Size aScreenSize( m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ) ); + Point aTL( rGeom.nLeftDecoration, rGeom.nTopDecoration ); + if( m_pSalDisplay->IsXinerama() ) + { + Point aMed( aTL.X() + rGeom.nWidth/2, aTL.Y() + rGeom.nHeight/2 ); + const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens(); + for( unsigned int i = 0; i < rScreens.size(); i++ ) + if( rScreens[i].IsInside( aMed ) ) + { + aTL += rScreens[i].TopLeft(); + aScreenSize = rScreens[i].GetSize(); + break; + } + } + Rectangle aTarget( aTL, + Size( aScreenSize.Width() - rGeom.nLeftDecoration - rGeom.nTopDecoration, + aScreenSize.Height() - rGeom.nTopDecoration - rGeom.nBottomDecoration ) + ); + if( ! bHorizontal ) + { + aTarget.SetSize( + Size( + pFrame->maRestorePosSize.IsEmpty() ? + rGeom.nWidth : pFrame->maRestorePosSize.GetWidth(), + aTarget.GetHeight() + ) + ); + aTarget.Left() = + pFrame->maRestorePosSize.IsEmpty() ? + rGeom.nX : pFrame->maRestorePosSize.Left(); + } + else if( ! bVertical ) + { + aTarget.SetSize( + Size( + aTarget.GetWidth(), + pFrame->maRestorePosSize.IsEmpty() ? + rGeom.nHeight : pFrame->maRestorePosSize.GetHeight() + ) + ); + aTarget.Top() = + pFrame->maRestorePosSize.IsEmpty() ? + rGeom.nY : pFrame->maRestorePosSize.Top(); + } + + Rectangle aRestore( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) ); + if( pFrame->bMapped_ ) + { + XSetInputFocus( m_pDisplay, + pFrame->GetShellWindow(), + RevertToNone, + CurrentTime + ); + if( m_aWMName.EqualsAscii( "Dtwm" ) ) + { + /* + * Dtwm will only position correctly with center gravity + * and in this case the request actually changes the frame + * not the shell window + */ + aTarget = Rectangle( Point( 0, 0 ), aScreenSize ); + aRestore.Move( -rGeom.nLeftDecoration, -rGeom.nTopDecoration ); + } + } + + if( pFrame->maRestorePosSize.IsEmpty() ) + pFrame->maRestorePosSize = aRestore; + + pFrame->SetPosSize( aTarget ); + pFrame->nWidth_ = aTarget.GetWidth(); + pFrame->nHeight_ = aTarget.GetHeight(); + XRaiseWindow( m_pDisplay, + pFrame->GetShellWindow() + ); + if( pFrame->GetStackingWindow() ) + XRaiseWindow( m_pDisplay, + pFrame->GetStackingWindow() + ); + + } + else + { + pFrame->SetPosSize( pFrame->maRestorePosSize ); + pFrame->maRestorePosSize = Rectangle(); + pFrame->nWidth_ = rGeom.nWidth; + pFrame->nHeight_ = rGeom.nHeight; + if( m_aWMName.EqualsAscii( "Dtwm" ) && pFrame->bMapped_ ) + { + pFrame->maGeometry.nX += rGeom.nLeftDecoration; + pFrame->maGeometry.nY += rGeom.nTopDecoration; + } + } +} + +/* + * NetWMAdaptor::maximizeFrame + * changes _NET_WM_STATE by sending a client message + */ + +void NetWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const +{ + pFrame->mbMaximizedVert = bVertical; + pFrame->mbMaximizedHorz = bHorizontal; + + if( m_aWMAtoms[ NET_WM_STATE ] + && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] + && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] + && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) + ) + { + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = bHorizontal ? 1 : 0; + aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ]; + aEvent.xclient.data.l[2] = bHorizontal == bVertical ? m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] : 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + if( bHorizontal != bVertical ) + { + aEvent.xclient.data.l[0]= bVertical ? 1 : 0; + aEvent.xclient.data.l[1]= m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ]; + aEvent.xclient.data.l[2]= 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + } + else + { + // window not mapped yet, set _NET_WM_STATE directly + setNetWMState( pFrame ); + } + if( !bHorizontal && !bVertical ) + pFrame->maRestorePosSize = Rectangle(); + else if( pFrame->maRestorePosSize.IsEmpty() ) + { + const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); + pFrame->maRestorePosSize = + Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) ); + } + } + else + WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical ); +} + +/* + * GnomeWMAdaptor::maximizeFrame + * changes _WIN_STATE by sending a client message + */ + +void GnomeWMAdaptor::maximizeFrame( X11SalFrame* pFrame, bool bHorizontal, bool bVertical ) const +{ + pFrame->mbMaximizedVert = bVertical; + pFrame->mbMaximizedHorz = bHorizontal; + + if( m_aWMAtoms[ WIN_STATE ] + && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) + ) + { + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = (1<<2)|(1<<3); + aEvent.xclient.data.l[1] = + (bVertical ? (1<<2) : 0) + | (bHorizontal ? (1<<3) : 0); + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask, + &aEvent + ); + } + else + // window not mapped yet, set _WIN_STATE directly + setGnomeWMState( pFrame ); + + if( !bHorizontal && !bVertical ) + pFrame->maRestorePosSize = Rectangle(); + else if( pFrame->maRestorePosSize.IsEmpty() ) + { + const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); + pFrame->maRestorePosSize = + Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) ); + } + } + else + WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical ); +} + +/* + * WMAdaptor::supportsICCCMPos + */ + +bool WMAdaptor::supportsICCCMPos() const +{ + return + m_aWMName.EqualsAscii( "Sawfish" ) + || m_aWMName.EqualsAscii( "Dtwm" ); +} + +/* + * NetWMAdaptor::supportsICCCMPos + */ + +bool NetWMAdaptor::supportsICCCMPos() const +{ + return true; +} + + +/* + * WMAdaptor::enableAlwaysOnTop + */ +void WMAdaptor::enableAlwaysOnTop( X11SalFrame*, bool /*bEnable*/ ) const +{ +} + +/* + * NetWMAdaptor::enableAlwaysOnTop + */ +void NetWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const +{ + pFrame->bAlwaysOnTop_ = bEnable; + if( m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ] ) + { + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = bEnable ? 1 : 0; + aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_STAYS_ON_TOP ]; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + else + setNetWMState( pFrame ); + } +} + +/* + * GnomeWMAdaptor::enableAlwaysOnTop + */ +void GnomeWMAdaptor::enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const +{ + pFrame->bAlwaysOnTop_ = bEnable; + if( m_aWMAtoms[ WIN_LAYER ] ) + { + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ WIN_LAYER ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = bEnable ? 6 : 4; + aEvent.xclient.data.l[1] = 0; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + else + { + sal_uInt32 nNewLayer = bEnable ? 6 : 4; + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ WIN_LAYER ], + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&nNewLayer, + 1 + ); + } + } +} + +/* + * WMAdaptor::changeReferenceFrame + */ +void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame* pReferenceFrame ) const +{ + if( ! ( pFrame->nStyle_ & SAL_FRAME_STYLE_PLUG ) + && ! pFrame->IsOverrideRedirect() + && ! pFrame->IsFloatGrabWindow() + ) + { + XLIB_Window aTransient = pFrame->pDisplay_->GetRootWindow( pFrame->GetScreenNumber() ); + pFrame->mbTransientForRoot = true; + if( pReferenceFrame ) + { + aTransient = pReferenceFrame->GetShellWindow(); + pFrame->mbTransientForRoot = false; + } + XSetTransientForHint( m_pDisplay, + pFrame->GetShellWindow(), + aTransient ); + } +} + +/* + * WMAdaptor::handlePropertyNotify + */ +int WMAdaptor::handlePropertyNotify( X11SalFrame*, XPropertyEvent* ) const +{ + return 0; +} + +/* + * NetWMAdaptor::handlePropertyNotify + */ +int NetWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const +{ + int nHandled = 1; + if( pEvent->atom == m_aWMAtoms[ NET_WM_STATE ] ) + { + pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false; + pFrame->mbShaded = false; + + if( pEvent->state == PropertyNewValue ) + { + Atom nType, *pStates; + int nFormat; + unsigned long nItems, nBytesLeft; + unsigned char* pData = NULL; + long nOffset = 0; + do + { + XGetWindowProperty( m_pDisplay, + pEvent->window, + m_aWMAtoms[ NET_WM_STATE ], + nOffset, 64, + False, + XA_ATOM, + &nType, + &nFormat, + &nItems, &nBytesLeft, + &pData ); + if( pData ) + { + if( nType == XA_ATOM && nFormat == 32 && nItems > 0 ) + { + pStates = (Atom*)pData; + for( unsigned long i = 0; i < nItems; i++ ) + { + if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_VERT ] ) + pFrame->mbMaximizedVert = true; + else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] && m_aWMAtoms[ NET_WM_STATE_MAXIMIZED_HORZ ] ) + pFrame->mbMaximizedHorz = true; + else if( pStates[i] == m_aWMAtoms[ NET_WM_STATE_SHADED ] && m_aWMAtoms[ NET_WM_STATE_SHADED ] ) + pFrame->mbShaded = true; + } + } + XFree( pData ); + pData = NULL; + nOffset += nItems * nFormat / 32; + } + else + break; + } while( nBytesLeft > 0 ); + } + + if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) ) + pFrame->maRestorePosSize = Rectangle(); + else + { + const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry(); + // the current geometry may already be changed by the corresponding + // ConfigureNotify, but this cannot be helped + pFrame->maRestorePosSize = + Rectangle( Point( rGeom.nX, rGeom.nY ), + Size( rGeom.nWidth, rGeom.nHeight ) ); + } + } + else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] ) + { + pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() ); + } + else + nHandled = 0; + + return nHandled; +} + +/* + * GnomeWMAdaptor::handlePropertyNotify + */ +int GnomeWMAdaptor::handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const +{ + int nHandled = 1; + if( pEvent->atom == m_aWMAtoms[ WIN_STATE ] ) + { + pFrame->mbMaximizedHorz = pFrame->mbMaximizedVert = false; + pFrame->mbShaded = false; + + if( pEvent->state == PropertyNewValue ) + { + Atom nType; + int nFormat = 0; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pData = 0; + XGetWindowProperty( m_pDisplay, + pEvent->window, + m_aWMAtoms[ WIN_STATE ], + 0, 1, + False, + XA_CARDINAL, + &nType, + &nFormat, + &nItems, &nBytesLeft, + &pData ); + if( pData ) + { + if( nType == XA_CARDINAL && nFormat == 32 && nItems == 1 ) + { + sal_uInt32 nWinState = *(sal_uInt32*)pData; + if( nWinState & (1<<2) ) + pFrame->mbMaximizedVert = true; + if( nWinState & (1<<3) ) + pFrame->mbMaximizedHorz = true; + if( nWinState & (1<<5) ) + pFrame->mbShaded = true; + } + XFree( pData ); + } + } + + if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) ) + pFrame->maRestorePosSize = Rectangle(); + else + { + const SalFrameGeometry& rGeom = pFrame->GetUnmirroredGeometry(); + // the current geometry may already be changed by the corresponding + // ConfigureNotify, but this cannot be helped + pFrame->maRestorePosSize = + Rectangle( Point( rGeom.nX, rGeom.nY ), + Size( rGeom.nWidth, rGeom.nHeight ) ); + } + } + else if( pEvent->atom == m_aWMAtoms[ NET_WM_DESKTOP ] ) + { + pFrame->m_nWorkArea = getWindowWorkArea( pFrame->GetShellWindow() ); + } + else + nHandled = 0; + + return nHandled; +} + +/* + * WMAdaptor::shade + */ +void WMAdaptor::shade( X11SalFrame*, bool /*bToShaded*/ ) const +{ +} + +/* + * NetWMAdaptor::shade + */ +void NetWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const +{ + if( m_aWMAtoms[ NET_WM_STATE ] + && m_aWMAtoms[ NET_WM_STATE_SHADED ] + && ( pFrame->nStyle_ & ~SAL_FRAME_STYLE_DEFAULT ) + ) + { + pFrame->mbShaded = bToShaded; + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = bToShaded ? 1 : 0; + aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_SHADED ]; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + else + { + // window not mapped yet, set _NET_WM_STATE directly + setNetWMState( pFrame ); + } + } +} + +/* + * GnomeWMAdaptor::shade + */ +void GnomeWMAdaptor::shade( X11SalFrame* pFrame, bool bToShaded ) const +{ + if( m_aWMAtoms[ WIN_STATE ] ) + { + pFrame->mbShaded = bToShaded; + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ WIN_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = (1<<5); + aEvent.xclient.data.l[1] = bToShaded ? (1<<5) : 0; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + else + setGnomeWMState( pFrame ); + } +} + +/* + * WMAdaptor::showFullScreen + */ +void WMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const +{ + pFrame->mbFullScreen = bFullScreen; + maximizeFrame( pFrame, bFullScreen, bFullScreen ); +} + +/* + * NetWMAdaptor::showFullScreen + */ +void NetWMAdaptor::showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const +{ + if( m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ] ) + { + pFrame->mbFullScreen = bFullScreen; + if( bFullScreen ) + { + if( m_aWMAtoms[ MOTIF_WM_HINTS ] ) + { + XDeleteProperty( m_pDisplay, + pFrame->GetShellWindow(), + m_aWMAtoms[ MOTIF_WM_HINTS ] ); + } + } + if( pFrame->bMapped_ ) + { + // window already mapped, send WM a message + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = pFrame->GetShellWindow(); + aEvent.xclient.message_type = m_aWMAtoms[ NET_WM_STATE ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = bFullScreen ? 1 : 0; + aEvent.xclient.data.l[1] = m_aWMAtoms[ NET_WM_STATE_FULLSCREEN ]; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } + else + { + // window not mapped yet, set _NET_WM_STATE directly + setNetWMState( pFrame ); + } + // #i42750# guess size before resize event shows up + if( bFullScreen ) + { + if( m_pSalDisplay->IsXinerama() ) + { + XLIB_Window aRoot, aChild; + int root_x = 0, root_y = 0, lx, ly; + unsigned int mask; + XQueryPointer( m_pDisplay, + m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), + &aRoot, &aChild, + &root_x, &root_y, &lx, &ly, &mask ); + const std::vector< Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens(); + Point aMousePoint( root_x, root_y ); + for( unsigned int i = 0; i < rScreens.size(); i++ ) + { + if( rScreens[i].IsInside( aMousePoint ) ) + { + pFrame->maGeometry.nX = rScreens[i].Left(); + pFrame->maGeometry.nY = rScreens[i].Top(); + pFrame->maGeometry.nWidth = rScreens[i].GetWidth(); + pFrame->maGeometry.nHeight = rScreens[i].GetHeight(); + break; + } + } + } + else + { + Size aSize = m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ); + pFrame->maGeometry.nX = 0; + pFrame->maGeometry.nY = 0; + pFrame->maGeometry.nWidth = aSize.Width(); + pFrame->maGeometry.nHeight = aSize.Height(); + } + pFrame->CallCallback( SALEVENT_MOVERESIZE, NULL ); + } + } + else WMAdaptor::showFullScreen( pFrame, bFullScreen ); +} + +/* + * WMAdaptor::getCurrentWorkArea + */ +// FIXME: multiscreen case +int WMAdaptor::getCurrentWorkArea() const +{ + int nCurrent = -1; + if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] ) + { + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + if( XGetWindowProperty( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + m_aWMAtoms[ NET_CURRENT_DESKTOP ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && pProperty + ) + { + nCurrent = int(*(sal_Int32*)pProperty); + XFree( pProperty ); + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + return nCurrent; +} + +/* + * WMAdaptor::getWindowWorkArea + */ +int WMAdaptor::getWindowWorkArea( XLIB_Window aWindow ) const +{ + int nCurrent = -1; + if( m_aWMAtoms[ NET_WM_DESKTOP ] ) + { + Atom aRealType = None; + int nFormat = 8; + unsigned long nItems = 0; + unsigned long nBytesLeft = 0; + unsigned char* pProperty = NULL; + if( XGetWindowProperty( m_pDisplay, + aWindow, + m_aWMAtoms[ NET_WM_DESKTOP ], + 0, 1, + False, + XA_CARDINAL, + &aRealType, + &nFormat, + &nItems, + &nBytesLeft, + &pProperty ) == 0 + && pProperty + ) + { + nCurrent = int(*(sal_Int32*)pProperty); + XFree( pProperty ); + } + else if( pProperty ) + { + XFree( pProperty ); + pProperty = NULL; + } + } + return nCurrent; +} + +/* + * WMAdaptor::getCurrentWorkArea + */ +// fixme: multi screen case +void WMAdaptor::switchToWorkArea( int nWorkArea, bool bConsiderWM ) const +{ + if( bConsiderWM && ! getWMshouldSwitchWorkspace() ) + return; + + if( m_aWMAtoms[ NET_CURRENT_DESKTOP ] ) + { + XEvent aEvent; + aEvent.type = ClientMessage; + aEvent.xclient.display = m_pDisplay; + aEvent.xclient.window = m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ); + aEvent.xclient.message_type = m_aWMAtoms[ NET_CURRENT_DESKTOP ]; + aEvent.xclient.format = 32; + aEvent.xclient.data.l[0] = nWorkArea; + aEvent.xclient.data.l[1] = 0; + aEvent.xclient.data.l[2] = 0; + aEvent.xclient.data.l[3] = 0; + aEvent.xclient.data.l[4] = 0; + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + } +} + +/* + * WMAdaptor::frameIsMapping + */ +void WMAdaptor::frameIsMapping( X11SalFrame* ) const +{ +} + +/* + * NetWMAdaptor::frameIsMapping + */ +void NetWMAdaptor::frameIsMapping( X11SalFrame* pFrame ) const +{ + setNetWMState( pFrame ); +} + +/* + * WMAdaptor::setFrameStruts + */ +void WMAdaptor::setFrameStruts( X11SalFrame*, + int, int, int, int, + int, int, int, int, + int, int, int, int ) const +{ +} + +/* + * NetWMAdaptor::setFrameStruts + */ +void NetWMAdaptor::setFrameStruts( X11SalFrame* pFrame, + int left, int right, int top, int bottom, + int left_start_y, int left_end_y, + int right_start_y, int right_end_y, + int top_start_x, int top_end_x, + int bottom_start_x, int bottom_end_x ) const +{ + long nData[12]; + nData[0] = left; + nData[1] = right; + nData[2] = top; + nData[3] = bottom; + nData[4] = left_start_y; + nData[5] = left_end_y; + nData[6] = right_start_y; + nData[7] = right_end_y; + nData[8] = top_start_x; + nData[9] = top_end_x; + nData[10]= bottom_start_x; + nData[11]= bottom_end_x; + Atom aProperty = None; + int nSetData = 0; + + if( m_aWMAtoms[NET_WM_STRUT_PARTIAL] ) + { + aProperty = m_aWMAtoms[NET_WM_STRUT_PARTIAL]; + nSetData = 12; + } + else if( m_aWMAtoms[NET_WM_STRUT] ) + { + aProperty = m_aWMAtoms[NET_WM_STRUT]; + nSetData = 4; + } + if( nSetData ) + { + XChangeProperty( m_pDisplay, + pFrame->GetShellWindow(), + aProperty, + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&nData, + nSetData + ); + } +} + +/* + * WMAdaptor::setUserTime + */ +void WMAdaptor::setUserTime( X11SalFrame*, long ) const +{ +} + +/* + * NetWMAdaptor::setUserTime + */ +void NetWMAdaptor::setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const +{ + if( m_aWMAtoms[NET_WM_USER_TIME] ) + { + XChangeProperty( m_pDisplay, + i_pFrame->GetShellWindow(), + m_aWMAtoms[NET_WM_USER_TIME], + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&i_nUserTime, + 1 + ); + } +} + +/* + * WMAdaptor::setPID + */ +void WMAdaptor::setPID( X11SalFrame* i_pFrame ) const +{ + if( m_aWMAtoms[NET_WM_PID] ) + { + long nPID = (long)getpid(); + XChangeProperty( m_pDisplay, + i_pFrame->GetShellWindow(), + m_aWMAtoms[NET_WM_PID], + XA_CARDINAL, + 32, + PropModeReplace, + (unsigned char*)&nPID, + 1 + ); + } +} + +/* +* WMAdaptor::setClientMachine +*/ +void WMAdaptor::setClientMachine( X11SalFrame* i_pFrame ) const +{ + rtl::OString aWmClient( rtl::OUStringToOString( GetX11SalData()->GetLocalHostName(), RTL_TEXTENCODING_ASCII_US ) ); + XTextProperty aClientProp = { (unsigned char*)aWmClient.getStr(), XA_STRING, 8, aWmClient.getLength() }; + XSetWMClientMachine( m_pDisplay, i_pFrame->GetShellWindow(), &aClientProp ); +} + +void WMAdaptor::answerPing( X11SalFrame* i_pFrame, XClientMessageEvent* i_pEvent ) const +{ + if( m_aWMAtoms[NET_WM_PING] && + i_pEvent->message_type == m_aWMAtoms[ WM_PROTOCOLS ] && + (Atom)i_pEvent->data.l[0] == m_aWMAtoms[ NET_WM_PING ] ) + { + XEvent aEvent; + aEvent.xclient = *i_pEvent; + aEvent.xclient.window = m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() ); + XSendEvent( m_pDisplay, + m_pSalDisplay->GetRootWindow( i_pFrame->GetScreenNumber() ), + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &aEvent + ); + XFlush( m_pDisplay ); + } +} |