/* -*- 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 <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <string_view>
#include <i18nlangtag/languagetag.hxx>
#include <rtl/locale.h>
#include <osl/thread.h>
#include <osl/process.h>
#include <sal/macros.h>
#include <sal/log.hxx>
#include <comphelper/string.hxx>
#include <configsettings.hxx>
#include <o3tl/string_view.hxx>
#include <unx/wmadaptor.hxx>
#include <unx/saldisp.hxx>
#include <unx/salframe.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
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 setFrameTypeAndDecoration( X11SalFrame* pFrame, WMWindowType eType,
int nDe
corationFlags, 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, tools::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 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
*/
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_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
*/
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 <const WMAdaptorProtocol*>(pLeft)->pProtocol, static_cast <const WMAdaptorProtocol*>(pRight)->pProtocol );
}
}
std::unique_ptr<WMAdaptor> WMAdaptor::createWMAdaptor( SalDisplay* pSalDisplay )
{
std::unique_ptr<WMAdaptor> 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< AbsoluteScreenPixelRectangle >
( 1, AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint(), 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() )
return ;
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 )
return ;
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 <Atom*>(pProperty);
char ** pAtomNames = static_cast <char **>(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 <WMAdaptorProtocol*>(
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 <long *>(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 <unsigned >(m_nDesktops)
)
{
m_aWMWorkAreas = ::std::vector< AbsoluteScreenPixelRectangle > ( m_nDesktops );
tools::Long * pValues = reinterpret_cast <long *>(pProperty);
for ( int i = 0; i < m_nDesktops; i++ )
{
AbsoluteScreenPixelPoint aPoint( pValues[4*i],
pValues[4*i+1] );
AbsoluteScreenPixelSize aSize( pValues[4*i+2],
pValues[4*i+3] );
AbsoluteScreenPixelRectangle 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 ] )
{
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
)
{
::Window aWMChild = *reinterpret_cast < ::Window* >(pProperty);
XFree( pProperty );
pProperty = nullptr;
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();
::Window 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 <Atom*>(pProperty);
char ** pAtomNames = static_cast <char **>(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 <WMAdaptorProtocol*>(
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 <long *>(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 ] )
{
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
)
{
::Window aWMChild = *reinterpret_cast < ::Window* >(pProperty);
XFree( pProperty );
pProperty = nullptr;
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();
::Window 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 <char *>(pProperty), nItems, RTL_TEXTENCODING_UTF8 );
else if (aRealType == XA_STRING)
m_aWMName = OUString( reinterpret_cast <char *>(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 <char *>(pProperty), nItems, RTL_TEXTENCODING_UTF8 );
sal_Int32 nIdx {0};
nVersionMajor = o3tl::toInt32(o3tl::getToken(aMetaVersion, 0, '.' , nIdx));
nVersionMinor = o3tl::toInt32(o3tl::getToken(aMetaVersion, 0, '.' , nIdx));
}
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 <WMAdaptor*>(this );
pWMA->m_bWMshouldSwitchWorkspace = true ;
vcl::SettingsConfigItem* pItem = vcl::SettingsConfigItem::get();
OUString aSetting( pItem->getValue( u"WM" _ustr,
u"ShouldSwitchWorkspace" _ustr ) );
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( std::u16string_view()));
aWMLocale = OUStringToOString( aLocaleString, RTL_TEXTENCODING_ISO_8859_1 );
}
else
{
static const char * pLang = getenv( "LANG" );
aWMLocale = pLang ? pLang : "C" ;
}
char * pT = const_cast <char *>(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 <unsigned char const *>(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();
::Window aShellWindow = pFrame->GetShellWindow();
XChangeProperty( m_pDisplay,
aShellWindow,
XA_WM_NAME,
nType,
nFormat,
PropModeReplace,
pData,
nBytes );
XChangeProperty( m_pDisplay,
aShellWindow,
XA_WM_ICON_NAME,
nType,
nFormat,
PropModeReplace,
pData,
nBytes );
XChangeProperty( m_pDisplay,
aShellWindow,
m_aWMAtoms[ WM_LOCALE_NAME ],
XA_STRING,
8,
PropModeReplace,
reinterpret_cast <unsigned char const *>(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));
::Window aShellWindow = pFrame->GetShellWindow();
if ( m_aWMAtoms[ NET_WM_NAME ] )
XChangeProperty( m_pDisplay,
aShellWindow,
m_aWMAtoms[ NET_WM_NAME ],
m_aWMAtoms[ UTF8_STRING ],
8,
PropModeReplace,
reinterpret_cast <unsigned char const *>(aTitle.getStr()),
aTitle.getLength() );
if ( m_aWMAtoms[ NET_WM_ICON_NAME ] )
XChangeProperty( m_pDisplay,
aShellWindow,
m_aWMAtoms[ NET_WM_ICON_NAME ],
m_aWMAtoms[ UTF8_STRING ],
8,
PropModeReplace,
reinterpret_cast <unsigned char const *>(aTitle.getStr()),
aTitle.getLength() );
}
/*
* NetWMAdaptor::setNetWMState
* sets _NET_WM_STATE
*/
void NetWMAdaptor::setNetWMState( X11SalFrame* pFrame ) const
{
if ( !(m_aWMAtoms[ NET_WM_STATE ]) )
return ;
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->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 <unsigned char *>(aStateAtoms),
nStateAtoms
);
}
else
XDeleteProperty( m_pDisplay,
pFrame->GetShellWindow(),
m_aWMAtoms[ NET_WM_STATE ] );
if ( !pFrame->mbMaximizedHorz
|| !pFrame->mbMaximizedVert
|| ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
return ;
/*
* for maximizing use NorthWestGravity (including decoration)
*/
XSizeHints hints;
tools::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;
}
AbsoluteScreenPixelRectangle aPosSize = m_aWMWorkAreas[nCurrent];
const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
aPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( aPosSize.Left() + aGeom.leftDecoration(),
aPosSize.Top() + aGeom.topDecoration() ),
AbsoluteScreenPixelSize( aPosSize.GetWidth()
- aGeom.leftDecoration()
- aGeom.rightDecoration(),
aPosSize.GetHeight()
- aGeom.topDecoration()
- aGeom.bottomDecoration() )
);
pFrame->SetPosSize( aPosSize );
/*
* reset gravity hint to static gravity
* (this should not move window according to ICCCM)
*/
if ( bHint && pFrame->nShowState_ != X11ShowState::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 ]) )
return ;
sal_uInt32 nWinWMState = 0;
if ( pFrame->mbMaximizedVert )
nWinWMState |= 1 << 2;
if ( pFrame->mbMaximizedHorz )
nWinWMState |= 1 << 3;
XChangeProperty( m_pDisplay,
pFrame->GetShellWindow(),
m_aWMAtoms[ WIN_STATE ],
XA_CARDINAL,
32,
PropModeReplace,
reinterpret_cast <unsigned char *>(&nWinWMState),
1
);
if ( !pFrame->mbMaximizedHorz
|| !pFrame->mbMaximizedVert
|| ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
return ;
/*
* for maximizing use NorthWestGravity (including decoration)
*/
XSizeHints hints;
tools::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;
}
AbsoluteScreenPixelRectangle aPosSize = m_aWMWorkAreas[nCurrent];
const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
aPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( aPosSize.Left() + aGeom.leftDecoration(),
aPosSize.Top() + aGeom.topDecoration() ),
AbsoluteScreenPixelSize( aPosSize.GetWidth()
- aGeom.leftDecoration()
- aGeom.rightDecoration(),
aPosSize.GetHeight()
- aGeom.topDecoration()
- aGeom.bottomDecoration() )
);
pFrame->SetPosSize( aPosSize );
/*
* reset gravity hint to static gravity
* (this should not move window according to ICCCM)
*/
if ( bHint && pFrame->nShowState_ != X11ShowState::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;
tools::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 <unsigned char *>(&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 <unsigned char *>(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 aGeom( 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 )
{
AbsoluteScreenPixelSize aScreenSize( m_pSalDisplay->GetScreenSize( pFrame->GetScreenNumber() ) );
AbsoluteScreenPixelPoint aTL( aGeom.leftDecoration(), aGeom.topDecoration() );
if ( m_pSalDisplay->IsXinerama() )
{
AbsoluteScreenPixelPoint aMed( aTL.X() + aGeom.width()/2, aTL.Y() + aGeom.height()/2 );
const std::vector< AbsoluteScreenPixelRectangle >& rScreens = m_pSalDisplay->GetXineramaScreens();
for (const auto & rScreen : rScreens)
if ( rScreen.Contains( aMed ) )
{
aTL += rScreen.TopLeft();
aScreenSize = rScreen.GetSize();
break ;
}
}
AbsoluteScreenPixelRectangle aTarget( aTL,
AbsoluteScreenPixelSize( aScreenSize.Width() - aGeom.leftDecoration() - aGeom.topDecoration(),
aScreenSize.Height() - aGeom.topDecoration() - aGeom.bottomDecoration() )
);
const AbsoluteScreenPixelRectangle aReferenceGeometry = !pFrame->maRestorePosSize.IsEmpty() ?
pFrame->maRestorePosSize : AbsoluteScreenPixelRectangle(aGeom.posSize());
if ( ! bHorizontal )
{
aTarget.SetSize({ aReferenceGeometry.GetWidth(), aTarget.GetHeight() });
aTarget.SetLeft(aReferenceGeometry.Left());
}
else if ( ! bVertical )
{
aTarget.SetSize({ aTarget.GetWidth(), aReferenceGeometry.GetHeight() });
aTarget.SetTop(aReferenceGeometry.Top());
}
AbsoluteScreenPixelRectangle aRestore(aGeom.posSize());
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 = AbsoluteScreenPixelRectangle();
pFrame->nWidth_ = aGeom.width();
pFrame->nHeight_ = aGeom.height();
}
}
/*
* 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 = AbsoluteScreenPixelRectangle();
else if ( pFrame->maRestorePosSize.IsEmpty() )
{
const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
pFrame->maRestorePosSize =
AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( aGeom.x(), aGeom.y() ), AbsoluteScreenPixelSize( aGeom.width(), aGeom.height() ) );
}
}
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 = AbsoluteScreenPixelRectangle();
else if ( pFrame->maRestorePosSize.IsEmpty() )
{
const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
pFrame->maRestorePosSize =
AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( aGeom.x(), aGeom.y() ), AbsoluteScreenPixelSize( aGeom.width(), aGeom.height() ) );
}
}
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 ]) )
return ;
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 ]) )
return ;
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 <unsigned char *>(&nNewLayer),
1
);
}
}
/*
* WMAdaptor::changeReferenceFrame
*/
void WMAdaptor::changeReferenceFrame( X11SalFrame* pFrame, X11SalFrame const * pReferenceFrame ) const
{
if ( ( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
|| pFrame->IsOverrideRedirect()
|| pFrame->IsFloatGrabWindow()
)
return ;
::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 ;
if ( pEvent->state == PropertyNewValue )
{
Atom nType, *pStates;
int nFormat;
unsigned long nItems, nBytesLeft;
unsigned char * pData = nullptr;
tools::Long nOffset = 0;
do
{
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=92 H=97 G=94
¤ Dauer der Verarbeitung: 0.23 Sekunden
¤
*© Formatika GbR, Deutschland