/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace vcl_sal { class NetWMAdaptor : public WMAdaptor { void setNetWMState( X11SalFrame* pFrame ) const; void initAtoms(); virtual bool isValid() const override; public: explicit NetWMAdaptor( SalDisplay* ); virtual void setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const override; virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const override; virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const override; virtual void setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType, int nDecorationFlags, X11SalFrame* pTransientFrame ) const override; virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const override; virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const override; virtual void showFullScreen( X11SalFrame* pFrame, bool bFullScreen ) const override; virtual void frameIsMapping( X11SalFrame* pFrame ) const override; virtual void setUserTime( X11SalFrame* i_pFrame, long i_nUserTime ) const override; }; class GnomeWMAdaptor : public WMAdaptor { bool m_bValid; void setGnomeWMState( X11SalFrame* pFrame ) const; void initAtoms(); virtual bool isValid() const override; public: explicit GnomeWMAdaptor( SalDisplay * ); virtual void maximizeFrame( X11SalFrame* pFrame, bool bHorizontal = true, bool bVertical = true ) const override; virtual void shade( X11SalFrame* pFrame, bool bToShaded ) const override; virtual void enableAlwaysOnTop( X11SalFrame* pFrame, bool bEnable ) const override; virtual int handlePropertyNotify( X11SalFrame* pFrame, XPropertyEvent* pEvent ) const override; }; } using namespace vcl_sal; namespace { 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_ACTIVE_WINDOW", WMAdaptor::NET_ACTIVE_WINDOW }, { "_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", WMAdaptor::NET_WM_ICON }, { "_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_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 }, { "_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( static_cast(pLeft)->pProtocol, static_cast(pRight)->pProtocol ); } } std::unique_ptr WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay ) { std::unique_ptr pAdaptor; // try a NetWM pAdaptor.reset(new NetWMAdaptor( pSalDisplay )); if( ! pAdaptor->isValid() ) { pAdaptor.reset(); } #if OSL_DEBUG_LEVEL > 1 else SAL_INFO("vcl.app", "WM supports extended WM hints."); #endif // try a GnomeWM if( ! pAdaptor ) { pAdaptor.reset(new GnomeWMAdaptor( pSalDisplay )); if( ! pAdaptor->isValid() ) { pAdaptor.reset(); } #if OSL_DEBUG_LEVEL > 1 else SAL_INFO("vcl.app", "WM supports GNOME WM hints."); #endif } if( ! pAdaptor ) pAdaptor.reset(new WMAdaptor( pSalDisplay )); #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", "Window Manager's name is \"" << pAdaptor->getWindowManagerName() << "\"."); #endif return pAdaptor; } /* * WMAdaptor constructor */ WMAdaptor::WMAdaptor( SalDisplay* pDisplay ) : m_pSalDisplay( pDisplay ), 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 = nullptr; // default desktops m_nDesktops = 1; m_aWMWorkAreas = ::std::vector< tools::Rectangle > ( 1, tools::Rectangle( Point(), m_pSalDisplay->GetScreenSize( m_pSalDisplay->GetDefaultXScreen() ) ) ); m_bEqualWorkAreas = true; memset( m_aWMAtoms, 0, sizeof( m_aWMAtoms ) ); m_pDisplay = m_pSalDisplay->GetDisplay(); initAtoms(); getNetWmName(); // try to discover e.g. Sawfish if( m_aWMName.isEmpty() ) { // 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->GetDefaultXScreen() ), aRwmRunning, 0, 32, False, aRwmRunning, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 ) { if( aRealType == aRwmRunning ) m_aWMName = "ReflectionX"; XFree( pProperty ); } else { aRwmRunning = XInternAtom( m_pDisplay, "_WRQ_WM_RUNNING", True ); if( aRwmRunning != None && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), aRwmRunning, 0, 32, False, XA_STRING, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 ) { if( aRealType == XA_STRING ) m_aWMName = "ReflectionX Windows"; XFree( pProperty ); } } } if( m_aWMName.isEmpty() ) { Atom aTTAPlatform = XInternAtom( m_pDisplay, "TTA_CLIENT_PLATFORM", True ); if( aTTAPlatform != None && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), aTTAPlatform, 0, 32, False, XA_STRING, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 ) { if( aRealType == XA_STRING ) { m_aWMName = "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 Atom aRealType = None; int nFormat = 8; unsigned long nItems = 0; unsigned long nBytesLeft = 0; unsigned char* pProperty = nullptr; initAtoms(); // check for NetWM bool bNetWM = getNetWmName(); if( bNetWM && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), 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 = nullptr; } // collect supported protocols if( XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ NET_SUPPORTED ], 0, nBytesLeft/4, False, XA_ATOM, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && nItems ) { Atom* pAtoms = reinterpret_cast(pProperty); char** pAtomNames = static_cast(alloca( sizeof(char*)*nItems )); if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) ) { #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", "supported protocols:"); #endif for( unsigned long i = 0; i < nItems; i++ ) { // #i80971# protect against invalid atoms if( pAtomNames[i] == nullptr ) continue; WMAdaptorProtocol aSearch; aSearch.pProtocol = pAtomNames[i]; WMAdaptorProtocol* pMatch = static_cast( bsearch( &aSearch, aProtocolTab, SAL_N_ELEMENTS( aProtocolTab ), sizeof( struct WMAdaptorProtocol ), compareProtocol )); if( pMatch ) { m_aWMAtoms[ pMatch->nProtocol ] = pAtoms[ i ]; if( pMatch->nProtocol == NET_WM_STATE_STAYS_ON_TOP ) m_bEnableAlwaysOnTopWorks = true; } #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", " " << pAtomNames[i] << (((pMatch)&&(pMatch->nProtocol != -1)) ? "" : " (unsupported)")); #endif XFree( pAtomNames[i] ); } } XFree( pProperty ); pProperty = nullptr; } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } // get number of desktops if( m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ] && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ NET_NUMBER_OF_DESKTOPS ], 0, 1, False, XA_CARDINAL, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && pProperty ) { m_nDesktops = *reinterpret_cast(pProperty); XFree( pProperty ); pProperty = nullptr; // get work areas if( m_aWMAtoms[ NET_WORKAREA ] && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ NET_WORKAREA ], 0, 4*m_nDesktops, False, XA_CARDINAL, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && nItems == 4*static_cast(m_nDesktops) ) { m_aWMWorkAreas = ::std::vector< tools::Rectangle > ( m_nDesktops ); long* pValues = reinterpret_cast(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] ); tools::Rectangle aWorkArea( aPoint, aSize ); m_aWMWorkAreas[i] = aWorkArea; if( aWorkArea != m_aWMWorkAreas[0] ) m_bEqualWorkAreas = false; #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", "workarea " << i << ": " << m_aWMWorkAreas[i].GetWidth() << "x" << m_aWMWorkAreas[i].GetHeight() << "+" << m_aWMWorkAreas[i].Left() << "+" << m_aWMWorkAreas[i].Top()); #endif } XFree( pProperty ); } else { #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", nItems/4 << " workareas for " << m_nDesktops << " desktops !"); #endif if( pProperty ) { XFree(pProperty); pProperty = nullptr; } } } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } /* * GnomeWMAdaptor constructor */ GnomeWMAdaptor::GnomeWMAdaptor( SalDisplay* pSalDisplay ) : WMAdaptor( pSalDisplay ), m_bValid( false ) { // currently all Gnome WMs do transient like expected Atom aRealType = None; int nFormat = 8; unsigned long nItems = 0; unsigned long nBytesLeft = 0; unsigned char* pProperty = nullptr; initAtoms(); // check for GnomeWM if( m_aWMAtoms[ WIN_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ WIN_PROTOCOLS ] ) { ::Window aWMChild = None; if( XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), 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 = *reinterpret_cast< ::Window* >(pProperty); XFree( pProperty ); pProperty = nullptr; ::Window aCheckWindow = None; GetGenericUnixSalData()->ErrorTrapPush(); 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 ) { if (! GetGenericUnixSalData()->ErrorTrapPop( false ) ) { GetGenericUnixSalData()->ErrorTrapPush(); aCheckWindow = *reinterpret_cast< ::Window* >(pProperty); XFree( pProperty ); pProperty = nullptr; 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(); } } else GetGenericUnixSalData()->ErrorTrapPush(); } GetGenericUnixSalData()->ErrorTrapPop(); } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } if( m_bValid && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), 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 = nullptr; } // collect supported protocols if( XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ WIN_PROTOCOLS ], 0, nBytesLeft/4, False, XA_ATOM, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && pProperty ) { Atom* pAtoms = reinterpret_cast(pProperty); char** pAtomNames = static_cast(alloca( sizeof(char*)*nItems )); if( XGetAtomNames( m_pDisplay, pAtoms, nItems, pAtomNames ) ) { #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", "supported protocols:"); #endif for( unsigned long i = 0; i < nItems; i++ ) { // #i80971# protect against invalid atoms if( pAtomNames[i] == nullptr ) continue; WMAdaptorProtocol aSearch; aSearch.pProtocol = pAtomNames[i]; WMAdaptorProtocol* pMatch = static_cast( bsearch( &aSearch, aProtocolTab, SAL_N_ELEMENTS( aProtocolTab ), sizeof( struct WMAdaptorProtocol ), compareProtocol )); if( pMatch ) { m_aWMAtoms[ pMatch->nProtocol ] = pAtoms[ i ]; if( pMatch->nProtocol == WIN_LAYER ) m_bEnableAlwaysOnTopWorks = true; } if( strncmp( "_ICEWM_TRAY", pAtomNames[i], 11 ) == 0 ) { m_aWMName = "IceWM"; m_nWinGravity = NorthWestGravity; m_nInitWinGravity = NorthWestGravity; } #if OSL_DEBUG_LEVEL > 1 SAL_INFO("vcl.app", " " << pAtomNames[i] << (((pMatch) && (pMatch->nProtocol != -1)) ? "" : " (unsupported)")); #endif XFree( pAtomNames[i] ); } } XFree( pProperty ); pProperty = nullptr; } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } // get number of desktops if( m_aWMAtoms[ WIN_WORKSPACE_COUNT ] && XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ WIN_WORKSPACE_COUNT ], 0, 1, False, XA_CARDINAL, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && pProperty ) { m_nDesktops = *reinterpret_cast(pProperty); XFree( pProperty ); pProperty = nullptr; } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } /* * getNetWmName() */ bool WMAdaptor::getNetWmName() { Atom aRealType = None; int nFormat = 8; unsigned long nItems = 0; unsigned long nBytesLeft = 0; unsigned char* pProperty = nullptr; bool bNetWM = false; if( m_aWMAtoms[ NET_SUPPORTING_WM_CHECK ] && m_aWMAtoms[ NET_WM_NAME ] ) { ::Window aWMChild = None; if( XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), 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 = *reinterpret_cast< ::Window* >(pProperty); XFree( pProperty ); pProperty = nullptr; ::Window aCheckWindow = None; GetGenericUnixSalData()->ErrorTrapPush(); 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 ) { if ( ! GetGenericUnixSalData()->ErrorTrapPop( false ) ) { GetGenericUnixSalData()->ErrorTrapPush(); aCheckWindow = *reinterpret_cast< ::Window* >(pProperty); XFree( pProperty ); pProperty = nullptr; 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 = OUString( reinterpret_cast(pProperty), nItems, RTL_TEXTENCODING_UTF8 ); else if (aRealType == XA_STRING) m_aWMName = OUString( reinterpret_cast(pProperty), nItems, RTL_TEXTENCODING_ISO_8859_1 ); XFree( pProperty ); pProperty = nullptr; } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } // if this is metacity, check for version to enable a legacy workaround if( m_aWMName == "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 ) { OUString aMetaVersion( reinterpret_cast(pProperty), nItems, RTL_TEXTENCODING_UTF8 ); sal_Int32 nIdx {0}; nVersionMajor = aMetaVersion.getToken(0, '.', nIdx).toInt32(); nVersionMinor = aMetaVersion.getToken(0, '.', nIdx).toInt32(); } if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } if( nVersionMajor < 2 || (nVersionMajor == 2 && nVersionMinor < 12) ) m_bLegacyPartialFullscreen = true; } } } else { if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } GetGenericUnixSalData()->ErrorTrapPush(); } } GetGenericUnixSalData()->ErrorTrapPop(); } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } return bNetWM; } bool WMAdaptor::getWMshouldSwitchWorkspace() const { if( ! m_bWMshouldSwitchWorkspaceInit ) { WMAdaptor * pWMA = const_cast(this); pWMA->m_bWMshouldSwitchWorkspace = true; vcl::SettingsConfigItem* pItem = vcl::SettingsConfigItem::get(); OUString aSetting( pItem->getValue( "WM", "ShouldSwitchWorkspace" ) ); if( aSetting.isEmpty() ) { if( m_aWMName == "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(const WMAdaptorProtocol & i : aAtomTab) m_aWMAtoms[ i.nProtocol ] = XInternAtom( m_pDisplay, 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 OUString& rWMName ) const { OString aTitle(OUStringToOString(rWMName, osl_getThreadTextEncoding())); OString aWMLocale; rtl_Locale* pLocale = nullptr; osl_getProcessLocale( &pLocale ); if( pLocale ) { OUString aLocaleString( LanguageTag( *pLocale).getGlibcLocaleString( OUString())); aWMLocale = OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 ); } else { static const char* pLang = getenv( "LANG" ); aWMLocale = pLang ? pLang : "C"; } char* pT = const_cast(aTitle.getStr()); XTextProperty aProp = { nullptr, None, 0, 0 }; XmbTextListToTextProperty( m_pDisplay, &pT, 1, XStdICCTextStyle, &aProp ); unsigned char const * pData = aProp.nitems ? aProp.value : reinterpret_cast(aTitle.getStr()); Atom nType = aProp.nitems ? aProp.encoding : XA_STRING; int nFormat = aProp.nitems ? aProp.format : 8; int nBytes = aProp.nitems ? aProp.nitems : aTitle.getLength(); const SystemEnvData* pEnv = pFrame->GetSystemData(); XChangeProperty( m_pDisplay, static_cast<::Window>(pEnv->aShellWindow), XA_WM_NAME, nType, nFormat, PropModeReplace, pData, nBytes ); XChangeProperty( m_pDisplay, static_cast<::Window>(pEnv->aShellWindow), XA_WM_ICON_NAME, nType, nFormat, PropModeReplace, pData, nBytes ); XChangeProperty( m_pDisplay, static_cast<::Window>(pEnv->aShellWindow), m_aWMAtoms[ WM_LOCALE_NAME ], XA_STRING, 8, PropModeReplace, reinterpret_cast(aWMLocale.getStr()), aWMLocale.getLength() ); if (aProp.value != nullptr) XFree( aProp.value ); } /* * NetWMAdaptor::setWMName * sets WM_NAME * _NET_WM_NAME * WM_ICON_NAME * _NET_WM_ICON_NAME */ void NetWMAdaptor::setWMName( X11SalFrame* pFrame, const OUString& rWMName ) const { WMAdaptor::setWMName( pFrame, rWMName ); OString aTitle(OUStringToOString(rWMName, RTL_TEXTENCODING_UTF8)); const SystemEnvData* pEnv = pFrame->GetSystemData(); if( m_aWMAtoms[ NET_WM_NAME ] ) XChangeProperty( m_pDisplay, static_cast<::Window>(pEnv->aShellWindow), m_aWMAtoms[ NET_WM_NAME ], m_aWMAtoms[ UTF8_STRING ], 8, PropModeReplace, reinterpret_cast(aTitle.getStr()), aTitle.getLength() ); if( m_aWMAtoms[ NET_WM_ICON_NAME ] ) XChangeProperty( m_pDisplay, static_cast<::Window>(pEnv->aShellWindow), m_aWMAtoms[ NET_WM_ICON_NAME ], m_aWMAtoms[ UTF8_STRING ], 8, PropModeReplace, reinterpret_cast(aTitle.getStr()), aTitle.getLength() ); } /* * 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( 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 == WMWindowType::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, reinterpret_cast(aStateAtoms), nStateAtoms ); } else XDeleteProperty( m_pDisplay, pFrame->GetShellWindow(), m_aWMAtoms[ NET_WM_STATE ] ); if( pFrame->mbMaximizedHorz && pFrame->mbMaximizedVert && ! ( pFrame->nStyle_ & SalFrameStyleFlags::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; } tools::Rectangle aPosSize = m_aWMWorkAreas[nCurrent]; const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); aPosSize = tools::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, reinterpret_cast(&nWinWMState), 1 ); if( pFrame->mbMaximizedHorz && pFrame->mbMaximizedVert && ! ( pFrame->nStyle_ & SalFrameStyleFlags::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; } tools::Rectangle aPosSize = m_aWMWorkAreas[nCurrent]; const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); aPosSize = tools::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; 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 = 1 << 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 |= 1 << 3; if( nDecorationFlags & decoration_Border ) aHint.deco |= 1 << 1; if( nDecorationFlags & decoration_Resize ) { aHint.deco |= 1 << 2; aHint.func |= 1 << 1; } if( nDecorationFlags & decoration_MinimizeBtn ) { aHint.deco |= 1 << 5; aHint.func |= 1 << 3; } if( nDecorationFlags & decoration_MaximizeBtn ) { aHint.deco |= 1 << 6; aHint.func |= 1 << 4; } if( nDecorationFlags & decoration_CloseBtn ) { aHint.deco |= 1 << 4; aHint.func |= 1 << 5; } } // set the hint XChangeProperty( m_pDisplay, pFrame->GetShellWindow(), m_aWMAtoms[ MOTIF_WM_HINTS ], m_aWMAtoms[ MOTIF_WM_HINTS ], 32, PropModeReplace, reinterpret_cast(&aHint), 5 ); } // set transientFor hint /* #91030# dtwm will not map a dialogue if the transient * window is iconified. This is deemed undesirable 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; } } /* * 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 WMWindowType::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 WMWindowType::ModelessDialogue: aWindowTypes[nWindowTypes++] = m_aWMAtoms[ NET_WM_WINDOW_TYPE_DIALOG ]; break; case WMWindowType::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 WMWindowType::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 WMWindowType::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, reinterpret_cast(aWindowTypes), nWindowTypes ); } if( ( eType == WMWindowType::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< tools::Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens(); for(const auto & rScreen : rScreens) if( rScreen.IsInside( aMed ) ) { aTL += rScreen.TopLeft(); aScreenSize = rScreen.GetSize(); break; } } tools::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.SetLeft( 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.SetTop( pFrame->maRestorePosSize.IsEmpty() ? rGeom.nY : pFrame->maRestorePosSize.Top() ); } tools::Rectangle aRestore( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) ); if( pFrame->bMapped_ ) { XSetInputFocus( m_pDisplay, pFrame->GetShellWindow(), RevertToNone, CurrentTime ); } 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 = tools::Rectangle(); pFrame->nWidth_ = rGeom.nWidth; pFrame->nHeight_ = rGeom.nHeight; } } /* * 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_ & ~SalFrameStyleFlags::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 = tools::Rectangle(); else if( pFrame->maRestorePosSize.IsEmpty() ) { const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); pFrame->maRestorePosSize = tools::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_ & ~SalFrameStyleFlags::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 = tools::Rectangle(); else if( pFrame->maRestorePosSize.IsEmpty() ) { const SalFrameGeometry& rGeom( pFrame->GetUnmirroredGeometry() ); pFrame->maRestorePosSize = tools::Rectangle( Point( rGeom.nX, rGeom.nY ), Size( rGeom.nWidth, rGeom.nHeight ) ); } } else WMAdaptor::maximizeFrame( pFrame, bHorizontal, bVertical ); } /* * 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, reinterpret_cast(&nNewLayer), 1 ); } } } /* * WMAdaptor::changeReferenceFrame */ void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame const * pReferenceFrame ) const { if( ! ( pFrame->nStyle_ & SalFrameStyleFlags::PLUG ) && ! pFrame->IsOverrideRedirect() && ! pFrame->IsFloatGrabWindow() ) { ::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 = nullptr; 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 = reinterpret_cast(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 = nullptr; nOffset += nItems * nFormat / 32; } else break; } while( nBytesLeft > 0 ); } if( ! (pFrame->mbMaximizedHorz || pFrame->mbMaximizedVert ) ) pFrame->maRestorePosSize = tools::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 = tools::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 = nullptr; 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 = *reinterpret_cast(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 = tools::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 = tools::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_ & ~SalFrameStyleFlags::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() ) { ::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< tools::Rectangle >& rScreens = m_pSalDisplay->GetXineramaScreens(); Point aMousePoint( root_x, root_y ); for(const auto & rScreen : rScreens) { if( rScreen.IsInside( aMousePoint ) ) { pFrame->maGeometry.nX = rScreen.Left(); pFrame->maGeometry.nY = rScreen.Top(); pFrame->maGeometry.nWidth = rScreen.GetWidth(); pFrame->maGeometry.nHeight = rScreen.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, nullptr ); } } 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 = nullptr; if( XGetWindowProperty( m_pDisplay, m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ), m_aWMAtoms[ NET_CURRENT_DESKTOP ], 0, 1, False, XA_CARDINAL, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && pProperty ) { nCurrent = int(*reinterpret_cast(pProperty)); XFree( pProperty ); } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } return nCurrent; } /* * WMAdaptor::getWindowWorkArea */ int WMAdaptor::getWindowWorkArea( ::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 = nullptr; if( XGetWindowProperty( m_pDisplay, aWindow, m_aWMAtoms[ NET_WM_DESKTOP ], 0, 1, False, XA_CARDINAL, &aRealType, &nFormat, &nItems, &nBytesLeft, &pProperty ) == 0 && pProperty ) { nCurrent = int(*reinterpret_cast(pProperty)); XFree( pProperty ); } else if( pProperty ) { XFree( pProperty ); pProperty = nullptr; } } return nCurrent; } /* * WMAdaptor::getCurrentWorkArea */ // fixme: multi screen case void WMAdaptor::switchToWorkArea( int nWorkArea ) const { if( ! getWMshouldSwitchWorkspace() ) return; if( !m_aWMAtoms[ NET_CURRENT_DESKTOP ] ) return; XEvent aEvent; aEvent.type = ClientMessage; aEvent.xclient.display = m_pDisplay; aEvent.xclient.window = m_pSalDisplay->GetRootWindow( m_pSalDisplay->GetDefaultXScreen() ); 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->GetDefaultXScreen() ), False, SubstructureNotifyMask | SubstructureRedirectMask, &aEvent ); } /* * WMAdaptor::frameIsMapping */ void WMAdaptor::frameIsMapping( X11SalFrame* ) const { } /* * NetWMAdaptor::frameIsMapping */ void NetWMAdaptor::frameIsMapping( X11SalFrame* pFrame ) const { setNetWMState( pFrame ); } /* * 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, reinterpret_cast(&i_nUserTime), 1 ); } } /* * WMAdaptor::setPID */ void WMAdaptor::setPID( X11SalFrame const * i_pFrame ) const { if( m_aWMAtoms[NET_WM_PID] ) { long nPID = static_cast(getpid()); XChangeProperty( m_pDisplay, i_pFrame->GetShellWindow(), m_aWMAtoms[NET_WM_PID], XA_CARDINAL, 32, PropModeReplace, reinterpret_cast(&nPID), 1 ); } } /* * WMAdaptor::setClientMachine */ void WMAdaptor::setClientMachine( X11SalFrame const * i_pFrame ) const { OString aWmClient( OUStringToOString( GetGenericUnixSalData()->GetHostname(), RTL_TEXTENCODING_ASCII_US ) ); XTextProperty aClientProp = { reinterpret_cast(const_cast(aWmClient.getStr())), XA_STRING, 8, sal::static_int_cast( aWmClient.getLength() ) }; XSetWMClientMachine( m_pDisplay, i_pFrame->GetShellWindow(), &aClientProp ); } void WMAdaptor::answerPing( X11SalFrame const * i_pFrame, XClientMessageEvent const * i_pEvent ) const { if( m_aWMAtoms[NET_WM_PING] && i_pEvent->message_type == m_aWMAtoms[ WM_PROTOCOLS ] && static_cast(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 ); } } void WMAdaptor::activateWindow( X11SalFrame const *pFrame, Time nTimestamp ) { if (!pFrame->bMapped_) return; XEvent aEvent; aEvent.xclient.type = ClientMessage; aEvent.xclient.window = pFrame->GetShellWindow(); aEvent.xclient.message_type = m_aWMAtoms[ NET_ACTIVE_WINDOW ]; aEvent.xclient.format = 32; aEvent.xclient.data.l[0] = 1; aEvent.xclient.data.l[1] = nTimestamp; aEvent.xclient.data.l[2] = None; aEvent.xclient.data.l[3] = 0; aEvent.xclient.data.l[4] = 0; XSendEvent( m_pDisplay, m_pSalDisplay->GetRootWindow( pFrame->GetScreenNumber() ), False, SubstructureNotifyMask | SubstructureRedirectMask, &aEvent ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */