/* -*- 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 <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#if defined(__sun)
#include <osl/module.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include <X11/cursorfont.h>
#include <unx/x11_cursors/salcursors.h>
#include <unx/x11_cursors/invert50.h>
#ifdef __sun
#define XK_KOREAN
#endif
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xinerama.h>
#include <i18nlangtag/languagetag.hxx>
#include <tools/debug.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <sal/log.hxx>
#include <sal/types.h>
#include <unx/i18n_im.hxx>
#include <unx/i18n_xkb.hxx>
#include <unx/saldisp.hxx>
#include <unx/saldata.hxx>
#include <salinst.hxx>
#include <unx/salframe.h>
#include <vcl/keycodes.hxx>
#include <osl/diagnose.h>
#include <unx/salobj.h>
#include <unx/sm.hxx>
#include <unx/wmadaptor.hxx>
#include <unx/glyphcache.hxx>
#include <o3tl/string_view.hxx>
#include <poll.h>
#include <memory>
#include <vector>
/* From <X11/Intrinsic.h> */
typedef unsigned long Pixel;
using namespace vcl_sal;
#ifdef DBG_UTIL
static const char *Null( const char *p ) { return p ? p : ""; }
static const char *GetEnv( const char *p ) { return Null( getenv( p ) ); }
static const char *KeyStr( KeySym n ) { return Null( XKeysymToString( n ) ); }
static const char *GetAtomName( Display *d, Atom a )
{ return Null( XGetAtomName( d, a ) ); }
#endif
// check if the resolution is sane
static bool sal_ValidDPI(tools::Long nDPI)
{
return (nDPI >= 50) && (nDPI <= 500);
}
static bool sal_GetVisualInfo( Display *pDisplay, XID nVID, XVisualInfo &rVI )
{
int nInfos;
XVisualInfo aTemplate;
XVisualInfo*pInfo;
aTemplate.visualid = nVID;
pInfo = XGetVisualInfo( pDisplay, VisualIDMask, &aTemplate, &nInfos );
if( !pInfo )
return false;
rVI = *pInfo;
XFree( pInfo );
SAL_WARN_IF( rVI.visualid != nVID, "vcl",
"sal_GetVisualInfo: could not get correct visual by visualId" );
return true;
}
extern "C" srv_vendor_t
sal_GetServerVendor( Display *p_display )
{
struct vendor_t {
srv_vendor_t e_vendor; // vendor as enum
const char* p_name; // vendor name as returned by VendorString()
unsigned int n_len; // number of chars to compare
};
static const vendor_t vendorlist[] = {
{ vendor_sun, "Sun Microsystems, Inc.", 10 },
};
// handle regular server vendors
char *p_name = ServerVendor( p_display );
for (auto const & vendor : vendorlist)
{
if ( strncmp (p_name, vendor.p_name, vendor.n_len) == 0 )
return vendor.e_vendor;
}
// vendor not found in list
return vendor_unknown;
}
bool SalDisplay::BestVisual( Display *pDisplay,
int nScreen,
XVisualInfo &rVI )
{
VisualID nDefVID = XVisualIDFromVisual( DefaultVisual( pDisplay, nScreen ) );
VisualID nVID = 0;
char *pVID = getenv( "SAL_VISUAL" );
if( pVID )
sscanf( pVID, "%li", &nVID );
if( nVID && sal_GetVisualInfo( pDisplay, nVID, rVI ) )
return rVI.visualid == nDefVID;
XVisualInfo aVI;
aVI.screen = nScreen;
// get all visuals
int nVisuals;
XVisualInfo* pVInfos = XGetVisualInfo( pDisplay, VisualScreenMask,
&aVI, &nVisuals );
// pVInfos should contain at least one visual, otherwise
// we're in trouble
std::vector<int> aWeights(nVisuals);
int i;
for( i = 0; i < nVisuals; i++ )
{
bool bUsable = false;
int nTrueColor = 1;
if ( pVInfos[i].screen != nScreen )
{
bUsable = false;
}
else if( pVInfos[i].c_class == TrueColor )
{
nTrueColor = 2048;
if( pVInfos[i].depth == 24 )
bUsable = true;
}
else if( pVInfos[i].c_class == PseudoColor )
{
bUsable = true;
}
aWeights[i] = bUsable ? nTrueColor*pVInfos[i].depth : -1024;
aWeights[i] -= pVInfos[ i ].visualid;
}
int nBestVisual = 0;
int nBestWeight = -1024;
for( i = 0; i < nVisuals; i++ )
{
if (aWeights[i] > nBestWeight)
{
nBestWeight = aWeights[i];
nBestVisual = i;
}
}
rVI = pVInfos[ nBestVisual ];
XFree( pVInfos );
return rVI.visualid == nDefVID;
}
SalDisplay::SalDisplay( Display *display ) :
pXLib_( nullptr ),
mpKbdExtension( nullptr ),
pDisp_( display ),
m_nXDefaultScreen( 0 ),
nMaxRequestSize_( 0 ),
meServerVendor( vendor_unknown ),
bNumLockFromXS_( false ),
nNumLockIndex_( 0 ),
nShiftKeySym_( 0 ),
nCtrlKeySym_( 0 ),
nMod1KeySym_( 0 ),
m_bXinerama( false ),
m_nLastUserEventTime( CurrentTime )
{
#if OSL_DEBUG_LEVEL > 1
SAL_INFO("vcl.app", "SalDisplay::SalDisplay().");
#endif
GenericUnixSalData *pData = GetGenericUnixSalData();
SAL_WARN_IF( pData->GetDisplay(), "vcl", "Second SalDisplay created !!!" );
pData->SetDisplay( this );
m_nXDefaultScreen = SalX11Screen( DefaultScreen( pDisp_ ) );
}
SalDisplay::~SalDisplay()
{
#if OSL_DEBUG_LEVEL > 1
SAL_INFO("vcl.app", "SalDisplay::~SalDisplay().");
#endif
if( pDisp_ )
{
doDestruct();
#if OSL_DEBUG_LEVEL > 1
SAL_INFO("vcl.app", "display " << pDisp_ << " closed.");
#endif
pDisp_ = nullptr;
}
// don't do this in doDestruct since RandR extension adds hooks into Display
// that is XCloseDisplay still needs the RandR library if it was used
DeInitRandR();
}
void SalDisplay::doDestruct()
{
GenericUnixSalData *pData = GetGenericUnixSalData();
m_pWMAdaptor.reset();
FreetypeManager::get().ClearFontCache();
if( IsDisplay() )
{
delete mpKbdExtension;
mpKbdExtension = nullptr;
for( size_t i = 0; i < m_aScreens.size(); i++ )
{
ScreenData& rData = m_aScreens[i];
if( rData.m_bInit )
{
if( rData.m_aMonoGC != rData.m_aCopyGC )
XFreeGC( pDisp_, rData.m_aMonoGC );
XFreeGC( pDisp_, rData.m_aCopyGC );
XFreeGC( pDisp_, rData.m_aAndInvertedGC );
XFreeGC( pDisp_, rData.m_aAndGC );
XFreeGC( pDisp_, rData.m_aOrGC );
XFreeGC( pDisp_, rData.m_aStippleGC );
XFreePixmap( pDisp_, rData.m_hInvert50 );
XDestroyWindow( pDisp_, rData.m_aRefWindow );
Colormap aColMap = rData.m_aColormap.GetXColormap();
if( aColMap != None && aColMap != DefaultColormap( pDisp_, i ) )
XFreeColormap( pDisp_, aColMap );
}
}
for( const Cursor & aCsr : aPointerCache_ )
{
if( aCsr )
XFreeCursor( pDisp_, aCsr );
}
if( pXLib_ )
pXLib_->Remove( ConnectionNumber( pDisp_ ) );
}
if( pData->GetDisplay() == static_cast<const SalGenericDisplay *>( this ) )
pData->SetDisplay( nullptr );
}
static int DisplayHasEvent( int fd, void * data )
{
auto pDisplay = static_cast<SalX11Display *>(data);
SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
"wrong fd in DisplayHasEvent" );
if( ! pDisplay->IsDisplay() )
return 0;
bool result;
SolarMutexGuard aGuard;
result = pDisplay->IsEvent();
return int(result);
}
static int DisplayQueue( int fd, void * data )
{
auto pDisplay = static_cast<SalX11Display *>(data);
SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
"wrong fd in DisplayHasEvent" );
int result;
SolarMutexGuard aGuard;
result = XEventsQueued( pDisplay->GetDisplay(),
QueuedAfterReading );
return result;
}
static int DisplayYield( int fd, void * data )
{
auto pDisplay = static_cast<SalX11Display *>(data);
SAL_WARN_IF( ConnectionNumber( pDisplay->GetDisplay() ) != fd, "vcl",
"wrong fd in DisplayHasEvent" );
SolarMutexGuard aGuard;
pDisplay->Yield();
return 1;
}
SalX11Display::SalX11Display( Display *display )
: SalDisplay( display )
{
Init();
pXLib_ = GetX11SalData()->GetLib();
pXLib_->Insert( ConnectionNumber( pDisp_ ),
this,
reinterpret_cast<YieldFunc>(DisplayHasEvent),
reinterpret_cast<YieldFunc>(DisplayQueue),
reinterpret_cast<YieldFunc>(DisplayYield) );
}
SalX11Display::~SalX11Display()
{
#if OSL_DEBUG_LEVEL > 1
SAL_INFO("vcl.app", "SalX11Display::~SalX11Display().");
#endif
if( pDisp_ )
{
doDestruct();
XCloseDisplay( pDisp_ );
pDisp_ = nullptr;
}
}
void SalX11Display::TriggerUserEventProcessing()
{
if( pXLib_ )
pXLib_->TriggerUserEventProcessing();
}
SalDisplay::ScreenData *
SalDisplay::initScreen( SalX11Screen nXScreen ) const
{
if( nXScreen.getXScreen() >= m_aScreens.size() )
nXScreen = m_nXDefaultScreen;
ScreenData* pSD = const_cast<ScreenData *>(&m_aScreens[nXScreen.getXScreen()]);
if( pSD->m_bInit )
return nullptr;
pSD->m_bInit = true;
XVisualInfo aVI;
Colormap aColMap;
if( SalDisplay::BestVisual( pDisp_, nXScreen.getXScreen(), aVI ) ) // DefaultVisual
aColMap = DefaultColormap( pDisp_, nXScreen.getXScreen() );
else
aColMap = XCreateColormap( pDisp_,
RootWindow( pDisp_, nXScreen.getXScreen() ),
aVI.visual,
AllocNone );
Screen* pScreen = ScreenOfDisplay( pDisp_, nXScreen.getXScreen() );
pSD->m_aSize = AbsoluteScreenPixelSize( WidthOfScreen( pScreen ), HeightOfScreen( pScreen ) );
pSD->m_aRoot = RootWindow( pDisp_, nXScreen.getXScreen() );
pSD->m_aVisual = SalVisual( &aVI );
pSD->m_aColormap = SalColormap( this, aColMap, nXScreen );
// we're interested in configure notification of root windows
InitRandR( pSD->m_aRoot );
// - - - - - - - - - - Reference Window/Default Drawable - -
XSetWindowAttributes aXWAttributes;
aXWAttributes.border_pixel = 0;
aXWAttributes.background_pixel = 0;
aXWAttributes.colormap = aColMap;
pSD->m_aRefWindow = XCreateWindow( pDisp_,
pSD->m_aRoot,
0,0, 16,16, 0,
pSD->m_aVisual.GetDepth(),
InputOutput,
pSD->m_aVisual.GetVisual(),
CWBorderPixel|CWBackPixel|CWColormap,
&aXWAttributes );
// set client leader (session id gets set when session is started)
if( pSD->m_aRefWindow )
{
// client leader must have WM_CLIENT_LEADER pointing to itself
XChangeProperty( pDisp_,
pSD->m_aRefWindow,
XInternAtom( pDisp_, "WM_CLIENT_LEADER", False ),
XA_WINDOW,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&pSD->m_aRefWindow),
1
);
OString aExec(OUStringToOString(SessionManagerClient::getExecName(), osl_getThreadTextEncoding()));
const char* argv[1];
argv[0] = aExec.getStr();
XSetCommand( pDisp_, pSD->m_aRefWindow, const_cast<char**>(argv), 1 );
XSelectInput( pDisp_, pSD->m_aRefWindow, PropertyChangeMask );
// - - - - - - - - - - GCs - - - - - - - - - - - - - - - - -
XGCValues values;
values.graphics_exposures = False;
values.fill_style = FillOpaqueStippled;
values.background = (1<<pSD->m_aVisual.GetDepth())-1;
values.foreground = 0;
pSD->m_aCopyGC = XCreateGC( pDisp_,
pSD->m_aRefWindow,
GCGraphicsExposures
| GCForeground
| GCBackground,
&values );
pSD->m_aAndInvertedGC= XCreateGC( pDisp_,
pSD->m_aRefWindow,
GCGraphicsExposures
| GCForeground
| GCBackground,
&values );
pSD->m_aAndGC = XCreateGC( pDisp_,
pSD->m_aRefWindow,
GCGraphicsExposures
| GCForeground
| GCBackground,
&values );
pSD->m_aOrGC = XCreateGC( pDisp_,
pSD->m_aRefWindow,
GCGraphicsExposures
| GCForeground
| GCBackground,
&values );
pSD->m_aStippleGC = XCreateGC( pDisp_,
pSD->m_aRefWindow,
GCGraphicsExposures
| GCFillStyle
| GCForeground
| GCBackground,
&values );
XSetFunction( pDisp_, pSD->m_aAndInvertedGC, GXandInverted );
XSetFunction( pDisp_, pSD->m_aAndGC, GXand );
// PowerPC Solaris 2.5 (XSun 3500) Bug: GXor = GXnop
XSetFunction( pDisp_, pSD->m_aOrGC, GXxor );
if( 1 == pSD->m_aVisual.GetDepth() )
{
XSetFunction( pDisp_, pSD->m_aCopyGC, GXcopyInverted );
pSD->m_aMonoGC = pSD->m_aCopyGC;
}
else
{
Pixmap hPixmap = XCreatePixmap( pDisp_, pSD->m_aRefWindow, 1, 1, 1 );
pSD->m_aMonoGC = XCreateGC( pDisp_,
hPixmap,
GCGraphicsExposures,
&values );
XFreePixmap( pDisp_, hPixmap );
}
pSD->m_hInvert50 = XCreateBitmapFromData( pDisp_,
pSD->m_aRefWindow,
reinterpret_cast<const char*>(invert50_bits),
invert50_width,
invert50_height );
}
return pSD;
}
void SalDisplay::Init()
{
for( Cursor & aCsr : aPointerCache_ )
aCsr = None;
m_bXinerama = false;
int nDisplayScreens = ScreenCount( pDisp_ );
m_aScreens = std::vector<ScreenData>(nDisplayScreens);
bool bExactResolution = false;
/* #i15507#
* Xft resolution should take precedence since
* it is what modern desktops use.
*/
const char* pValStr = XGetDefault( pDisp_, "Xft", "dpi" );
if( pValStr != nullptr )
{
const tools::Long nDPI = static_cast<tools::Long>(o3tl::toDouble(std::string_view(pValStr)));
// guard against insane resolution
if( sal_ValidDPI(nDPI) )
{
aResolution_ = Pair( nDPI, nDPI );
bExactResolution = true;
}
}
if( !bExactResolution )
{
/* if Xft.dpi is not set, try and find the DPI from the
* reported screen sizes and resolution. If there are multiple
* screens, just fall back to the default 96x96
*/
tools::Long xDPI = 96;
tools::Long yDPI = 96;
if (m_aScreens.size() == 1) {
xDPI = static_cast<tools::Long>(round(DisplayWidth(pDisp_, 0)*25.4/DisplayWidthMM(pDisp_, 0)));
yDPI = static_cast<tools::Long>(round(DisplayHeight(pDisp_, 0)*25.4/DisplayHeightMM(pDisp_, 0)));
// if either is invalid set it equal to the other
if (!sal_ValidDPI(xDPI) && sal_ValidDPI(yDPI))
xDPI = yDPI;
if (!sal_ValidDPI(yDPI) && sal_ValidDPI(xDPI))
yDPI = xDPI;
// if both are invalid, reset them to the default
if (!sal_ValidDPI(xDPI) && !sal_ValidDPI(yDPI))
xDPI = yDPI = 96;
}
aResolution_ = Pair( xDPI, yDPI );
}
nMaxRequestSize_ = XExtendedMaxRequestSize( pDisp_ ) * 4;
if( !nMaxRequestSize_ )
nMaxRequestSize_ = XMaxRequestSize( pDisp_ ) * 4;
meServerVendor = sal_GetServerVendor(pDisp_);
// - - - - - - - - - - Synchronize - - - - - - - - - - - - -
if( getenv( "SAL_SYNCHRONIZE" ) )
XSynchronize( pDisp_, True );
// - - - - - - - - - - Keyboardmapping - - - - - - - - - - -
ModifierMapping();
// - - - - - - - - - - Window Manager - - - - - - - - - - -
m_pWMAdaptor = ::vcl_sal::WMAdaptor::createWMAdaptor( this );
InitXinerama();
#ifdef DBG_UTIL
PrintInfo();
#endif
}
void SalX11Display::SetupInput()
{
GetGenericUnixSalData()->ErrorTrapPush();
SalI18N_KeyboardExtension *pKbdExtension = new SalI18N_KeyboardExtension( pDisp_ );
XSync( pDisp_, False );
bool bError = GetGenericUnixSalData()->ErrorTrapPop( false );
GetGenericUnixSalData()->ErrorTrapPush();
pKbdExtension->UseExtension( ! bError );
GetGenericUnixSalData()->ErrorTrapPop();
SetKbdExtension( pKbdExtension );
}
// Sound
void SalDisplay::Beep() const
{
XBell( pDisp_, 100 );
}
// Keyboard
namespace {
bool InitXkb(Display* dpy)
{
int nOpcode, nEvent, nError;
int nXkbMajor = XkbMajorVersion;
int nXkbMinor = XkbMinorVersion;
if (!XkbLibraryVersion(&nXkbMajor, &nXkbMinor))
return false;
return XkbQueryExtension(
dpy, &nOpcode, &nEvent, &nError, &nXkbMajor, &nXkbMinor);
}
unsigned int GetKeySymMask(Display* dpy, KeySym nKeySym)
{
int nMask = 0;
XModifierKeymap* pXmkMap = XGetModifierMapping(dpy);
KeyCode nKeyCode = XKeysymToKeycode(dpy, nKeySym);
if (nKeyCode == NoSymbol)
return 0;
for (int i = 0; i < 8; ++i)
{
KeyCode nThisKeyCode = pXmkMap->modifiermap[pXmkMap->max_keypermod*i];
if (nThisKeyCode == nKeyCode)
nMask = 1 << i;
}
XFreeModifiermap(pXmkMap);
return nMask;
}
}
void SalDisplay::SimulateKeyPress( sal_uInt16 nKeyCode )
{
if (nKeyCode != KEY_CAPSLOCK)
return;
Display* dpy = GetDisplay();
if (!InitXkb(dpy))
return;
unsigned int nMask = GetKeySymMask(dpy, XK_Caps_Lock);
XkbStateRec xkbState;
XkbGetState(dpy, XkbUseCoreKbd, &xkbState);
unsigned int nCapsLockState = xkbState.locked_mods & nMask;
if (nCapsLockState)
XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, 0);
else
XkbLockModifiers (dpy, XkbUseCoreKbd, nMask, nMask);
}
KeyIndicatorState SalDisplay::GetIndicatorState() const
{
unsigned int _state = 0;
KeyIndicatorState nState = KeyIndicatorState::NONE;
XkbGetIndicatorState(pDisp_, XkbUseCoreKbd, &_state);
if (_state & 0x00000001)
nState |= KeyIndicatorState::CAPSLOCK;
if (_state & 0x00000002)
nState |= KeyIndicatorState::NUMLOCK;
if (_state & 0x00000004)
nState |= KeyIndicatorState::SCROLLLOCK;
return nState;
}
OUString SalDisplay::GetKeyNameFromKeySym( KeySym nKeySym ) const
{
OUString aLang = Application::GetSettings().GetUILanguageTag().getLanguage();
OUString aRet;
// return an empty string for keysyms that are not bound to
// any key code
KeyCode aKeyCode = XKeysymToKeycode( GetDisplay(), nKeySym );
static_assert(NoSymbol == 0, "X11 inconsistency");
if( aKeyCode != NoSymbol )
{
if( !nKeySym )
aRet = "???";
else
{
aRet = ::vcl_sal::getKeysymReplacementName( aLang, nKeySym );
if( aRet.isEmpty() )
{
const char *pString = XKeysymToString( nKeySym );
if (pString)
{
int n = strlen( pString );
if( n > 2 && pString[n-2] == '_' )
aRet = OUString( pString, n-2, RTL_TEXTENCODING_ISO_8859_1 );
else
aRet = OUString( pString, n, RTL_TEXTENCODING_ISO_8859_1 );
}
else
aRet = "???";
}
}
}
return aRet;
}
static KeySym sal_XModifier2Keysym( Display *pDisplay,
XModifierKeymap const *pXModMap,
int n )
{
return XkbKeycodeToKeysym( pDisplay,
pXModMap->modifiermap[n*pXModMap->max_keypermod],
0,0 );
}
void SalDisplay::ModifierMapping()
{
XModifierKeymap *pXModMap = XGetModifierMapping( pDisp_ );
bNumLockFromXS_ = True;
nShiftKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ShiftMapIndex );
nCtrlKeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, ControlMapIndex );
nMod1KeySym_ = sal_XModifier2Keysym( pDisp_, pXModMap, Mod1MapIndex );
// on Sun and SCO servers XLookupString does not account for NumLock
if( GetServerVendor() == vendor_sun )
{
KeyCode aNumLock = XKeysymToKeycode( pDisp_, XK_Num_Lock );
if( aNumLock )
for( int i = ShiftMapIndex; i <= Mod5MapIndex; i++ )
{
if( pXModMap->modifiermap[i*pXModMap->max_keypermod] == aNumLock )
{
bNumLockFromXS_ = False;
nNumLockIndex_ = i;
break;
}
}
}
XFreeModifiermap( pXModMap );
}
OUString SalDisplay::GetKeyName( sal_uInt16 nKeyCode ) const
{
OUString aStrMap;
OUString aCustomKeyName;
if( nKeyCode & KEY_MOD1 )
aStrMap += GetKeyNameFromKeySym( nCtrlKeySym_ );
if( nKeyCode & KEY_MOD2 )
{
if( !aStrMap.isEmpty() )
aStrMap += "+";
aStrMap += GetKeyNameFromKeySym( nMod1KeySym_ );
}
if( nKeyCode & KEY_SHIFT )
{
if( !aStrMap.isEmpty() )
aStrMap += "+";
aStrMap += GetKeyNameFromKeySym( nShiftKeySym_ );
}
nKeyCode &= 0x0FFF;
KeySym nKeySym = 0;
if( KEY_0 <= nKeyCode && nKeyCode <= KEY_9 )
nKeySym = XK_0 + (nKeyCode - KEY_0);
else if( KEY_A <= nKeyCode && nKeyCode <= KEY_Z )
nKeySym = XK_A + (nKeyCode - KEY_A);
else if( KEY_F1 <= nKeyCode && nKeyCode <= KEY_F26 ) // does this key exist?
nKeySym = XK_F1 + (nKeyCode - KEY_F1);
else switch( nKeyCode )
{
case KEY_DOWN:
nKeySym = XK_Down;
break;
case KEY_UP:
nKeySym = XK_Up;
break;
case KEY_LEFT:
nKeySym = XK_Left;
break;
case KEY_RIGHT:
nKeySym = XK_Right;
break;
case KEY_HOME:
nKeySym = XK_Home;
break;
case KEY_END:
nKeySym = XK_End;
break;
case KEY_PAGEUP:
nKeySym = XK_Page_Up;
break;
case KEY_PAGEDOWN:
nKeySym = XK_Page_Down;
break;
case KEY_RETURN:
nKeySym = XK_Return;
break;
case KEY_ESCAPE:
nKeySym = XK_Escape;
break;
case KEY_TAB:
nKeySym = XK_Tab;
break;
case KEY_BACKSPACE:
nKeySym = XK_BackSpace;
break;
case KEY_SPACE:
nKeySym = XK_space;
break;
case KEY_INSERT:
nKeySym = XK_Insert;
break;
case KEY_DELETE:
nKeySym = XK_Delete;
break;
#if !defined (SunXK_Undo)
// we don't intend to use SunXK_Undo, but if it has not been
// defined already, then we _do_ need the following:
#define SunXK_Props 0x1005FF70
#define SunXK_Front 0x1005FF71
#define SunXK_Copy 0x1005FF72
#define SunXK_Open 0x1005FF73
#define SunXK_Paste 0x1005FF74
#define SunXK_Cut 0x1005FF75
#endif
// the following are for XF86 systems
#define XF86XK_Copy 0x1008FF57
#define XF86XK_Cut 0x1008FF58
#define XF86XK_Open 0x1008FF6B
#define XF86XK_Paste 0x1008FF6D
// which leaves Apollo and OSF systems in the lurch
case KEY_REPEAT:
nKeySym = XK_Redo;
break;
case KEY_PROPERTIES:
nKeySym = SunXK_Props;
break;
case KEY_UNDO:
nKeySym = XK_Undo;
break;
case KEY_FRONT:
nKeySym = SunXK_Front;
break;
case KEY_COPY:
nKeySym = GetServerVendor() == vendor_sun ? SunXK_Copy : XF86XK_Copy;
break;
case KEY_OPEN:
nKeySym = GetServerVendor() == vendor_sun ? SunXK_Open : XF86XK_Open;
break;
case KEY_PASTE:
nKeySym = GetServerVendor() == vendor_sun ? SunXK_Paste : XF86XK_Paste;
break;
case KEY_FIND:
nKeySym = XK_Find;
break;
case KEY_CUT:
nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XF86XK_Cut;
/* The original code here had:
nKeySym = GetServerVendor() == vendor_sun ? SunXK_Cut : XK_L10;
if anyone can remember which non-vendor_sun system used this
XK_L10 keysym, and why this hack only applied to KEY_CUT,
then please re-hack this code to put it back
*/
break;
case KEY_ADD:
aCustomKeyName = "+";
break;
case KEY_SUBTRACT:
aCustomKeyName = "-";
break;
case KEY_MULTIPLY:
nKeySym = XK_asterisk;
break;
case KEY_DIVIDE:
nKeySym = XK_slash;
break;
case KEY_POINT:
aCustomKeyName = ".";
break;
case KEY_COMMA:
nKeySym = XK_comma;
break;
case KEY_LESS:
nKeySym = XK_less;
break;
case KEY_GREATER:
nKeySym = XK_greater;
break;
case KEY_EQUAL:
nKeySym = XK_equal;
break;
case KEY_HELP:
nKeySym = XK_Help;
break;
case KEY_HANGUL_HANJA:
nKeySym = XK_Hangul_Hanja;
break;
case KEY_TILDE:
nKeySym = XK_asciitilde;
break;
case KEY_QUOTELEFT:
nKeySym = XK_grave;
break;
case KEY_BRACKETLEFT:
aCustomKeyName = "[";
break;
case KEY_BRACKETRIGHT:
aCustomKeyName = "]";
break;
case KEY_SEMICOLON:
aCustomKeyName = ";";
break;
case KEY_QUOTERIGHT:
aCustomKeyName = "'";
break;
case KEY_RIGHTCURLYBRACKET:
aCustomKeyName = "}";
break;
case KEY_NUMBERSIGN:
aCustomKeyName = "#";
break;
case KEY_XF86FORWARD:
aCustomKeyName = "XF86Forward";
break;
case KEY_XF86BACK:
aCustomKeyName = "XF86Back";
break;
case KEY_COLON:
aCustomKeyName = ":";
break;
default:
nKeySym = 0;
break;
}
if( nKeySym )
{
OUString aKeyName = GetKeyNameFromKeySym( nKeySym );
if( !aKeyName.isEmpty() )
{
if( !aStrMap.isEmpty() )
aStrMap += "+";
aStrMap += aKeyName;
}
else
aStrMap.clear();
}
else if (!aCustomKeyName.isEmpty())
{
// For semicolon, bracket left and bracket right, it's better to use
// their keys than their names. (fdo#32891)
if (!aStrMap.isEmpty())
aStrMap += "+";
aStrMap += aCustomKeyName;
}
else
aStrMap.clear();
return aStrMap;
}
#ifndef IsISOKey
#define IsISOKey( n ) (0x0000FE00==((n)&0xFFFFFF00))
#endif
sal_uInt16 SalDisplay::GetKeyCode( KeySym keysym, char*pcPrintable ) const
{
sal_uInt16 nKey = 0;
if( XK_a <= keysym && XK_z >= keysym )
nKey = static_cast<sal_uInt16>(KEY_A + (keysym - XK_a));
else if( XK_A <= keysym && XK_Z >= keysym )
nKey = static_cast<sal_uInt16>(KEY_A + (keysym - XK_A));
else if( XK_0 <= keysym && XK_9 >= keysym )
nKey = static_cast<sal_uInt16>(KEY_0 + (keysym - XK_0));
else if( IsModifierKey( keysym ) )
;
else if( IsKeypadKey( keysym ) )
{
if( (keysym >= XK_KP_0) && (keysym <= XK_KP_9) )
{
nKey = static_cast<sal_uInt16>(KEY_0 + (keysym - XK_KP_0));
*pcPrintable = '0' + nKey - KEY_0;
}
else if( IsPFKey( keysym ) )
nKey = static_cast<sal_uInt16>(KEY_F1 + (keysym - XK_KP_F1));
else switch( keysym )
{
case XK_KP_Space:
nKey = KEY_SPACE;
*pcPrintable = ' ';
break;
case XK_KP_Tab:
nKey = KEY_TAB;
break;
case XK_KP_Enter:
nKey = KEY_RETURN;
break;
case XK_KP_Begin:
case XK_KP_Home:
nKey = KEY_HOME;
break;
case XK_KP_Left:
nKey = KEY_LEFT;
break;
case XK_KP_Up:
nKey = KEY_UP;
break;
case XK_KP_Right:
nKey = KEY_RIGHT;
break;
case XK_KP_Down:
nKey = KEY_DOWN;
break;
case XK_KP_Page_Up: // XK_KP_Page_Up
nKey = KEY_PAGEUP;
break;
case XK_KP_Page_Down: // XK_KP_Page_Down
nKey = KEY_PAGEDOWN;
break;
case XK_KP_End:
nKey = KEY_END;
break;
case XK_KP_Insert:
nKey = KEY_INSERT;
break;
case XK_KP_Delete:
nKey = KEY_DELETE;
break;
case XK_KP_Equal:
nKey = KEY_EQUAL;
*pcPrintable = '=';
break;
case XK_KP_Multiply:
nKey = KEY_MULTIPLY;
*pcPrintable = '*';
break;
case XK_KP_Add:
nKey = KEY_ADD;
*pcPrintable = '+';
break;
case XK_KP_Separator:
nKey = KEY_DECIMAL;
*pcPrintable = ',';
break;
case XK_KP_Subtract:
nKey = KEY_SUBTRACT;
*pcPrintable = '-';
break;
case XK_KP_Decimal:
nKey = KEY_DECIMAL;
*pcPrintable = '.';
break;
case XK_KP_Divide:
nKey = KEY_DIVIDE;
*pcPrintable = '/';
break;
}
}
else if( IsFunctionKey( keysym ) )
{
if( bNumLockFromXS_ )
{
if( keysym >= XK_F1 && keysym <= XK_F26 )
nKey = static_cast<sal_uInt16>(KEY_F1 + keysym - XK_F1);
}
else switch( keysym )
{
// - - - - - Sun X-Server keyboard without Cursorblock ??? - - -
case XK_R7: // XK_F27:
nKey = KEY_HOME;
break;
case XK_R8: // XK_F28:
nKey = KEY_UP;
break;
case XK_R9: // XK_F29:
nKey = KEY_PAGEUP;
break;
case XK_R10: // XK_F30:
nKey = KEY_LEFT;
break;
case XK_R11: // XK_F31:
nKey = 0; // KEY_F31
break;
case XK_R12: // XK_F32:
nKey = KEY_RIGHT;
break;
case XK_R13: // XK_F33:
nKey = KEY_END;
break;
case XK_R14: // XK_F34:
nKey = KEY_DOWN;
break;
case XK_R15: // XK_F35:
nKey = KEY_PAGEDOWN;
break;
// - - - - - Sun X-Server keyboard ??? - - - - - - - - - - - -
case XK_L1: // XK_F11:
nKey = KEY_F11; // on a sun keyboard this actually is usually SunXK_Stop = 0x0000FF69 (XK_Cancel),
// but VCL doesn't have a key definition for that
break;
case XK_L2: // XK_F12:
if ( GetServerVendor() == vendor_sun )
nKey = KEY_REPEAT;
else
nKey = KEY_F12;
break;
case XK_L3: // XK_F13:
nKey = KEY_PROPERTIES; // KEY_F13
break;
case XK_L4: // XK_F14:
nKey = KEY_UNDO; // KEY_F14
break;
case XK_L5: // XK_F15:
nKey = KEY_F15; // KEY_FRONT
break;
case XK_L6: // XK_F16:
nKey = KEY_COPY; // KEY_F16
break;
case XK_L7: // XK_F17:
nKey = KEY_F17; // KEY_OPEN
break;
case XK_L8: // XK_F18:
nKey = KEY_PASTE; // KEY_F18
break;
case XK_L9: // XK_F19:
nKey = KEY_F19; // KEY_FIND
break;
case XK_L10: // XK_F20:
nKey = KEY_CUT; // KEY_F20
break;
default:
if( keysym >= XK_F1 && keysym <= XK_F26 )
nKey = static_cast<sal_uInt16>(KEY_F1 + keysym - XK_F1);
break;
}
}
else if( IsCursorKey( keysym ) )
{
switch( keysym )
{
case XK_Begin:
case XK_Home:
nKey = KEY_HOME;
break;
case XK_Left:
nKey = KEY_LEFT;
break;
case XK_Up:
nKey = KEY_UP;
break;
case XK_Right:
nKey = KEY_RIGHT;
break;
case XK_Down:
nKey = KEY_DOWN;
break;
case XK_Page_Up: // XK_Page_Up
nKey = KEY_PAGEUP;
break;
case XK_Page_Down: // XK_Page_Down
nKey = KEY_PAGEDOWN;
break;
case XK_End:
nKey = KEY_END;
break;
}
}
else if( IsMiscFunctionKey( keysym ) )
{
switch( keysym )
{
case XK_Insert:
nKey = KEY_INSERT;
break;
case XK_Redo:
nKey = KEY_REPEAT;
break;
case XK_Undo:
nKey = KEY_UNDO;
break;
case XK_Find:
nKey = KEY_FIND;
break;
case XK_Help:
nKey = KEY_HELP;
break;
case XK_Menu:
nKey = KEY_CONTEXTMENU;
break;
}
}
else if( IsISOKey( keysym ) ) // XK_ISO_
{
switch( keysym )
{
case 0xFE20: // XK_ISO_Left_Tab:
nKey = KEY_TAB;
break;
}
}
else switch( keysym )
{
case XK_Return:
nKey = KEY_RETURN;
break;
case XK_BackSpace:
nKey = KEY_BACKSPACE;
break;
case XK_Delete:
nKey = KEY_DELETE;
break;
case XK_space:
nKey = KEY_SPACE;
break;
case XK_Tab:
nKey = KEY_TAB;
break;
case XK_Escape:
nKey = KEY_ESCAPE;
break;
case XK_plus:
nKey = KEY_ADD;
break;
case XK_minus:
nKey = KEY_SUBTRACT;
break;
case XK_asterisk:
nKey = KEY_MULTIPLY;
break;
case XK_slash:
nKey = KEY_DIVIDE;
break;
case XK_period:
nKey = KEY_POINT;
*pcPrintable = '.';
break;
case XK_comma:
nKey = KEY_COMMA;
break;
case XK_less:
nKey = KEY_LESS;
break;
case XK_greater:
nKey = KEY_GREATER;
break;
case XK_equal:
nKey = KEY_EQUAL;
break;
case XK_Hangul_Hanja:
nKey = KEY_HANGUL_HANJA;
break;
case XK_asciitilde:
nKey = KEY_TILDE;
*pcPrintable = '~';
break;
case XK_grave:
nKey = KEY_QUOTELEFT;
*pcPrintable = '`';
break;
case XK_bracketleft:
nKey = KEY_BRACKETLEFT;
*pcPrintable = '[';
break;
case XK_bracketright:
nKey = KEY_BRACKETRIGHT;
*pcPrintable = ']';
break;
case XK_semicolon:
nKey = KEY_SEMICOLON;
*pcPrintable = ';';
break;
case XK_quoteright:
nKey = KEY_QUOTERIGHT;
*pcPrintable = '\'';
break;
case XK_braceright:
nKey = KEY_RIGHTCURLYBRACKET;
*pcPrintable = '\'';
break;
case XK_numbersign:
nKey = KEY_NUMBERSIGN;
*pcPrintable = '#';
break;
case XK_colon:
nKey = KEY_COLON;
*pcPrintable = ':';
break;
case 0x1008ff27: // tdf#148986: XF86Forward
nKey = KEY_XF86FORWARD;
break;
case 0x1008ff26: // tdf#148986: XF86Back
nKey = KEY_XF86BACK;
break;
// - - - - - - - - - - - - - Apollo - - - - - - - - - - - - - 0x1000
case 0x1000FF02: // apXK_Copy
nKey = KEY_COPY;
break;
case 0x1000FF03: // apXK_Cut
nKey = KEY_CUT;
break;
case 0x1000FF04: // apXK_Paste
nKey = KEY_PASTE;
break;
case 0x1000FF14: // apXK_Repeat
nKey = KEY_REPEAT;
break;
// Exit, Save
// - - - - - - - - - - - - - - D E C - - - - - - - - - - - - - 0x1000
case 0x1000FF00:
nKey = KEY_DELETE;
break;
// - - - - - - - - - - - - - - H P - - - - - - - - - - - - - 0x1000
case 0x1000FF73: // hpXK_DeleteChar
nKey = KEY_DELETE;
break;
case 0x1000FF74: // hpXK_BackTab
case 0x1000FF75: // hpXK_KP_BackTab
nKey = KEY_TAB;
break;
// - - - - - - - - - - - - - - I B M - - - - - - - - - - - - -
// - - - - - - - - - - - - - - O S F - - - - - - - - - - - - - 0x1004
case 0x1004FF02: // osfXK_Copy
nKey = KEY_COPY;
break;
case 0x1004FF03: // osfXK_Cut
nKey = KEY_CUT;
break;
case 0x1004FF04: // osfXK_Paste
nKey = KEY_PASTE;
break;
case 0x1004FF07: // osfXK_BackTab
nKey = KEY_TAB;
break;
case 0x1004FF08: // osfXK_BackSpace
nKey = KEY_BACKSPACE;
break;
case 0x1004FF1B: // osfXK_Escape
nKey = KEY_ESCAPE;
break;
// Up, Down, Left, Right, PageUp, PageDown
// - - - - - - - - - - - - - - S C O - - - - - - - - - - - - -
// - - - - - - - - - - - - - - S G I - - - - - - - - - - - - - 0x1007
// - - - - - - - - - - - - - - S N I - - - - - - - - - - - - -
// - - - - - - - - - - - - - - S U N - - - - - - - - - - - - - 0x1005
case 0x1005FF10: // SunXK_F36
nKey = KEY_F11;
break;
case 0x1005FF11: // SunXK_F37
nKey = KEY_F12;
break;
case 0x1005FF70: // SunXK_Props
nKey = KEY_PROPERTIES;
break;
case 0x1005FF71: // SunXK_Front
nKey = KEY_FRONT;
break;
case 0x1005FF72: // SunXK_Copy
nKey = KEY_COPY;
break;
case 0x1005FF73: // SunXK_Open
nKey = KEY_OPEN;
break;
case 0x1005FF74: // SunXK_Paste
nKey = KEY_PASTE;
break;
case 0x1005FF75: // SunXK_Cut
nKey = KEY_CUT;
break;
}
return nKey;
}
KeySym SalDisplay::GetKeySym( XKeyEvent *pEvent,
char *pPrintable,
int *pLen,
KeySym *pUnmodifiedKeySym,
Status *pStatusReturn,
XIC aInputContext ) const
{
KeySym nKeySym = 0;
memset( pPrintable, 0, *pLen );
*pStatusReturn = 0;
SalI18N_InputMethod* const pInputMethod =
pXLib_ ? pXLib_->GetInputMethod() : nullptr;
// first get the printable of the possibly modified KeySym
if ( (aInputContext == nullptr)
|| (pEvent->type == KeyRelease)
|| (pInputMethod != nullptr && pInputMethod->PosixLocale()) )
{
// XmbLookupString must not be called for KeyRelease events
// Cannot enter space in c locale problem #89616# #88978# btraq #4478197
*pLen = XLookupString( pEvent, pPrintable, 1, &nKeySym, nullptr );
}
else
{
*pLen = XmbLookupString( aInputContext,
pEvent, pPrintable, *pLen - 1, &nKeySym, pStatusReturn );
// Lookup the string again, now with appropriate size
if ( *pStatusReturn == XBufferOverflow )
{
pPrintable[ 0 ] = '\0';
return 0;
}
switch ( *pStatusReturn )
{
case XBufferOverflow:
/* unhandled error */
break;
case XLookupNone:
/* unhandled error */
break;
case XLookupKeySym:
/* this is a strange one: on exceed sometimes
* no printable is returned for the first char entered,
* just to retry lookup solves the problem. The problem
* is not yet fully understood, so restrict 2nd lookup
* to 7bit ascii chars */
if ( (XK_space <= nKeySym) && (XK_asciitilde >= nKeySym) )
{
*pLen = 1;
pPrintable[ 0 ] = static_cast<char>(nKeySym);
}
break;
case XLookupBoth:
case XLookupChars:
/* nothing to, char already in pPrintable */
break;
}
}
if( !bNumLockFromXS_
&& (IsCursorKey(nKeySym)
|| IsFunctionKey(nKeySym)
|| IsKeypadKey(nKeySym)
|| XK_Delete == nKeySym ) )
{
// For some X-servers special care is needed for Keypad keys.
// For example Solaris XServer:
// 2, 4, 6, 8 are classified as Cursorkeys (Up, Down, Left, Right)
// 1, 3, 5, 9 are classified as Functionkeys (F27,F29,F33,F35)
// 0 as Keypadkey, and the decimal point key not at all (KP_Insert)
KeySym nNewKeySym = XLookupKeysym( pEvent, nNumLockIndex_ );
if( nNewKeySym != NoSymbol )
nKeySym = nNewKeySym;
}
// Now get the unmodified KeySym for KeyCode retrieval
// try to strip off modifiers, e.g. Ctrl-$ becomes Ctrl-Shift-4
*pUnmodifiedKeySym = XkbKeycodeToKeysym( GetDisplay(), pEvent->keycode, 0, 0);
return nKeySym;
}
// Pointer
static unsigned char nullmask_bits[] = { 0x00, 0x00, 0x00, 0x00 };
static unsigned char nullcurs_bits[] = { 0x00, 0x00, 0x00, 0x00 };
#define MAKE_BITMAP( name ) \
XCreateBitmapFromData( pDisp_, \
DefaultRootWindow( pDisp_ ), \
reinterpret_cast<const char*>(name##_bits), \
name##_width, \
name##_height )
#define MAKE_CURSOR( name ) \
aCursBitmap = MAKE_BITMAP( name##curs ); \
aMaskBitmap = MAKE_BITMAP( name##mask ); \
nXHot = name##curs_x_hot; \
nYHot = name##curs_y_hot
Cursor SalDisplay::GetPointer( PointerStyle ePointerStyle )
{
Cursor &aCur = aPointerCache_[ePointerStyle];
if( aCur != None )
return aCur;
Pixmap aCursBitmap = None, aMaskBitmap = None;
unsigned int nXHot = 0, nYHot = 0;
switch( ePointerStyle )
{
case PointerStyle::Null:
MAKE_CURSOR( null );
break;
case PointerStyle::Arrow:
aCur = XCreateFontCursor( pDisp_, XC_left_ptr );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::Wait:
aCur = XCreateFontCursor( pDisp_, XC_watch );
break;
case PointerStyle::Text: // Mouse Pointer is a "I" Beam
aCur = XCreateFontCursor( pDisp_, XC_xterm );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::Help:
aCur = XCreateFontCursor( pDisp_, XC_question_arrow );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::Cross: // Mouse Pointer is a cross
aCur = XCreateFontCursor( pDisp_, XC_crosshair );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::NSize:
aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::SSize:
aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WSize:
aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::ESize:
aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowNSize:
aCur = XCreateFontCursor( pDisp_, XC_top_side );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowSSize:
aCur = XCreateFontCursor( pDisp_, XC_bottom_side );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowWSize:
aCur = XCreateFontCursor( pDisp_, XC_left_side );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowESize:
aCur = XCreateFontCursor( pDisp_, XC_right_side );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::NWSize:
aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
break;
case PointerStyle::NESize:
aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
break;
case PointerStyle::SWSize:
aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
break;
case PointerStyle::SESize:
aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
break;
case PointerStyle::WindowNWSize:
aCur = XCreateFontCursor( pDisp_, XC_top_left_corner );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowNESize:
aCur = XCreateFontCursor( pDisp_, XC_top_right_corner );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowSWSize:
aCur = XCreateFontCursor( pDisp_, XC_bottom_left_corner );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::WindowSESize:
aCur = XCreateFontCursor( pDisp_, XC_bottom_right_corner );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::HSplit:
aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow );
break;
case PointerStyle::VSplit:
aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow );
break;
case PointerStyle::HSizeBar:
aCur = XCreateFontCursor( pDisp_, XC_sb_h_double_arrow ); // ???
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::VSizeBar:
aCur = XCreateFontCursor( pDisp_, XC_sb_v_double_arrow ); // ???
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::RefHand:
aCur = XCreateFontCursor( pDisp_, XC_hand1 );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::Hand:
aCur = XCreateFontCursor( pDisp_, XC_hand2 );
break;
case PointerStyle::Magnify:
MAKE_CURSOR( magnify_ );
break;
case PointerStyle::Fill:
MAKE_CURSOR( fill_ );
break;
case PointerStyle::Move:
aCur = XCreateFontCursor( pDisp_, XC_fleur );
break;
case PointerStyle::MoveData:
MAKE_CURSOR( movedata_ );
break;
case PointerStyle::CopyData:
MAKE_CURSOR( copydata_ );
break;
case PointerStyle::MoveFile:
MAKE_CURSOR( movefile_ );
break;
case PointerStyle::CopyFile:
MAKE_CURSOR( copyfile_ );
break;
case PointerStyle::MoveFiles:
MAKE_CURSOR( movefiles_ );
break;
case PointerStyle::CopyFiles:
MAKE_CURSOR( copyfiles_ );
break;
case PointerStyle::NotAllowed:
MAKE_CURSOR( nodrop_ );
break;
case PointerStyle::Rotate:
MAKE_CURSOR( rotate_ );
break;
case PointerStyle::HShear:
MAKE_CURSOR( hshear_ );
break;
case PointerStyle::VShear:
MAKE_CURSOR( vshear_ );
break;
case PointerStyle::DrawLine:
MAKE_CURSOR( drawline_ );
break;
case PointerStyle::DrawRect:
MAKE_CURSOR( drawrect_ );
break;
case PointerStyle::DrawPolygon:
MAKE_CURSOR( drawpolygon_ );
break;
case PointerStyle::DrawBezier:
MAKE_CURSOR( drawbezier_ );
break;
case PointerStyle::DrawArc:
MAKE_CURSOR( drawarc_ );
break;
case PointerStyle::DrawPie:
MAKE_CURSOR( drawpie_ );
break;
case PointerStyle::DrawCircleCut:
MAKE_CURSOR( drawcirclecut_ );
break;
case PointerStyle::DrawEllipse:
MAKE_CURSOR( drawellipse_ );
break;
case PointerStyle::DrawConnect:
MAKE_CURSOR( drawconnect_ );
break;
case PointerStyle::DrawText:
MAKE_CURSOR( drawtext_ );
break;
case PointerStyle::Mirror:
MAKE_CURSOR( mirror_ );
break;
case PointerStyle::Crook:
MAKE_CURSOR( crook_ );
break;
case PointerStyle::Crop:
MAKE_CURSOR( crop_ );
break;
case PointerStyle::MovePoint:
MAKE_CURSOR( movepoint_ );
break;
case PointerStyle::MoveBezierWeight:
MAKE_CURSOR( movebezierweight_ );
break;
case PointerStyle::DrawFreehand:
MAKE_CURSOR( drawfreehand_ );
break;
case PointerStyle::DrawCaption:
MAKE_CURSOR( drawcaption_ );
break;
case PointerStyle::Pen: // Mouse Pointer is a pencil
aCur = XCreateFontCursor( pDisp_, XC_pencil );
SAL_WARN_IF( aCur == None, "vcl", "GetPointer: Could not define cursor" );
break;
case PointerStyle::LinkData:
MAKE_CURSOR( linkdata_ );
break;
case PointerStyle::MoveDataLink:
MAKE_CURSOR( movedlnk_ );
break;
case PointerStyle::CopyDataLink:
MAKE_CURSOR( copydlnk_ );
break;
case PointerStyle::LinkFile:
MAKE_CURSOR( linkfile_ );
break;
case PointerStyle::MoveFileLink:
MAKE_CURSOR( moveflnk_ );
break;
case PointerStyle::CopyFileLink:
MAKE_CURSOR( copyflnk_ );
break;
case PointerStyle::Chart:
MAKE_CURSOR( chart_ );
break;
case PointerStyle::Detective:
MAKE_CURSOR( detective_ );
break;
case PointerStyle::PivotCol:
MAKE_CURSOR( pivotcol_ );
break;
case PointerStyle::PivotRow:
MAKE_CURSOR( pivotrow_ );
break;
case PointerStyle::PivotField:
MAKE_CURSOR( pivotfld_ );
break;
case PointerStyle::PivotDelete:
MAKE_CURSOR( pivotdel_ );
break;
case PointerStyle::Chain:
MAKE_CURSOR( chain_ );
break;
case PointerStyle::ChainNotAllowed:
MAKE_CURSOR( chainnot_ );
break;
case PointerStyle::AutoScrollN:
MAKE_CURSOR(asn_ );
break;
case PointerStyle::AutoScrollS:
MAKE_CURSOR( ass_ );
break;
case PointerStyle::AutoScrollW:
MAKE_CURSOR( asw_ );
break;
case PointerStyle::AutoScrollE:
MAKE_CURSOR( ase_ );
break;
case PointerStyle::AutoScrollNW:
MAKE_CURSOR( asnw_ );
break;
case PointerStyle::AutoScrollNE:
MAKE_CURSOR( asne_ );
break;
case PointerStyle::AutoScrollSW:
MAKE_CURSOR( assw_ );
break;
case PointerStyle::AutoScrollSE:
MAKE_CURSOR( asse_ );
break;
case PointerStyle::AutoScrollNS:
MAKE_CURSOR( asns_ );
break;
case PointerStyle::AutoScrollWE:
MAKE_CURSOR( aswe_ );
break;
case PointerStyle::AutoScrollNSWE:
MAKE_CURSOR( asnswe_ );
break;
case PointerStyle::TextVertical:
MAKE_CURSOR( vertcurs_ );
break;
// #i32329# Enhanced table selection
case PointerStyle::TabSelectS:
MAKE_CURSOR( tblsels_ );
break;
case PointerStyle::TabSelectE:
MAKE_CURSOR( tblsele_ );
break;
case PointerStyle::TabSelectSE:
MAKE_CURSOR( tblselse_ );
break;
case PointerStyle::TabSelectW:
MAKE_CURSOR( tblselw_ );
break;
case PointerStyle::TabSelectSW:
MAKE_CURSOR( tblselsw_ );
break;
case PointerStyle::HideWhitespace:
MAKE_CURSOR( hidewhitespace_ );
break;
case PointerStyle::ShowWhitespace:
MAKE_CURSOR( showwhitespace_ );
break;
case PointerStyle::FatCross:
MAKE_CURSOR( fatcross_ );
break;
default:
OSL_FAIL("pointer not implemented");
aCur = XCreateFontCursor( pDisp_, XC_arrow );
break;
}
if( None == aCur )
{
XColor aBlack, aWhite, aDummy;
Colormap hColormap = GetColormap(m_nXDefaultScreen).GetXColormap();
XAllocNamedColor( pDisp_, hColormap, "black", &aBlack, &aDummy );
XAllocNamedColor( pDisp_, hColormap, "white", &aWhite, &aDummy );
aCur = XCreatePixmapCursor( pDisp_,
aCursBitmap, aMaskBitmap,
&aBlack, &aWhite,
nXHot, nYHot );
XFreePixmap( pDisp_, aCursBitmap );
XFreePixmap( pDisp_, aMaskBitmap );
}
return aCur;
}
int SalDisplay::CaptureMouse( SalFrame *pCapture )
{
static const char* pEnv = getenv( "SAL_NO_MOUSEGRABS" );
if( !pCapture )
{
m_pCapture = nullptr;
if( !pEnv || !*pEnv )
XUngrabPointer( GetDisplay(), CurrentTime );
XFlush( GetDisplay() );
return 0;
}
m_pCapture = nullptr;
// FIXME: get rid of X11SalFrame
const SystemEnvData* pEnvData = pCapture->GetSystemData();
if( !pEnv || !*pEnv )
{
int ret = XGrabPointer( GetDisplay(),
static_cast<::Window>(pEnvData->GetWindowHandle(pCapture)),
False,
PointerMotionMask| ButtonPressMask|ButtonReleaseMask,
GrabModeAsync,
GrabModeAsync,
None,
static_cast<X11SalFrame*>(pCapture)->GetCursor(),
CurrentTime );
if( ret != GrabSuccess )
{
SAL_WARN("vcl", "SalDisplay::CaptureMouse could not grab pointer: " << ret);
return -1;
}
}
m_pCapture = pCapture;
return 1;
}
// Events
bool SalX11Display::IsEvent()
{
if( HasUserEvents() || XEventsQueued( pDisp_, QueuedAlready ) )
return true;
XFlush( pDisp_ );
return false;
}
void SalX11Display::Yield()
{
if( DispatchInternalEvent() )
return;
XEvent aEvent;
DBG_ASSERT(GetSalInstance()->GetYieldMutex()->IsCurrentThread(),
"will crash soon since solar mutex not locked in SalDisplay::Yield" );
XNextEvent( pDisp_, &aEvent );
// coverity[overrun-buffer-val : FALSE] - coverity has problems with uno::Sequence
Dispatch( &aEvent );
#ifdef DBG_UTIL
if( GetX11SalData()->HasXErrorOccurred() )
{
XFlush( pDisp_ );
DbgPrintDisplayEvent("SalDisplay::Yield (WasXError)", &aEvent);
}
#endif
GetX11SalData()->ResetXErrorOccurred();
}
void SalX11Display::Dispatch( XEvent *pEvent )
{
SalI18N_InputMethod* const pInputMethod =
pXLib_ ? pXLib_->GetInputMethod() : nullptr;
if( pInputMethod )
{
::Window aFrameWindow = None;
if( pEvent->type == KeyPress || pEvent->type == KeyRelease )
{
const ::Window aWindow = pEvent->xkey.window;
for( auto pSalFrame : m_aFrames )
{
const X11SalFrame* pFrame = static_cast< const X11SalFrame* >( pSalFrame );
const ::Window aCurFrameWindow = pFrame->GetWindow();
if( aCurFrameWindow == aWindow || pFrame->GetShellWindow() == aWindow )
{
aFrameWindow = aCurFrameWindow;
break;
}
}
}
if( pInputMethod->FilterEvent( pEvent, aFrameWindow ) )
return;
}
SalInstance* pInstance = GetSalInstance();
pInstance->CallEventCallback( pEvent, sizeof( XEvent ) );
switch( pEvent->type )
{
case MotionNotify:
while( XCheckWindowEvent( pEvent->xany.display,
pEvent->xany.window,
ButtonMotionMask,
pEvent ) )
;
m_nLastUserEventTime = pEvent->xmotion.time;
break;
case PropertyNotify:
if( pEvent->xproperty.atom == getWMAdaptor()->getAtom( WMAdaptor::VCL_SYSTEM_SETTINGS ) )
{
for(const ScreenData & rScreen : m_aScreens)
{
if( pEvent->xproperty.window == rScreen.m_aRefWindow )
{
for (auto pSalFrame : m_aFrames )
pSalFrame->CallCallback( SalEvent::SettingsChanged, nullptr );
return;
}
}
}
break;
case MappingNotify:
if( MappingModifier == pEvent->xmapping.request )
{
XRefreshKeyboardMapping( &pEvent->xmapping );
ModifierMapping();
}
break;
case ButtonPress:
case ButtonRelease:
m_nLastUserEventTime = pEvent->xbutton.time;
break;
case KeyPress:
case KeyRelease:
m_nLastUserEventTime = pEvent->xkey.time;
break;
default:
if ( GetKbdExtension()->UseExtension()
&& GetKbdExtension()->GetEventBase() == pEvent->type )
{
GetKbdExtension()->Dispatch( pEvent );
return;
}
break;
}
for (auto pSalFrame : m_aFrames )
{
X11SalFrame* pFrame = static_cast<X11SalFrame*>( pSalFrame );
::Window aDispatchWindow = pEvent->xany.window;
if( pFrame->GetWindow() == aDispatchWindow
|| pFrame->GetShellWindow() == aDispatchWindow
|| pFrame->GetForeignParent() == aDispatchWindow
)
{
pFrame->Dispatch( pEvent );
return;
}
if( pEvent->type == ConfigureNotify && pEvent->xconfigure.window == pFrame->GetStackingWindow() )
{
pFrame->Dispatch( pEvent );
return;
}
}
// dispatch to salobjects
X11SalObject::Dispatch( pEvent );
// is this perhaps a root window that changed size ?
processRandREvent( pEvent );
}
#ifdef DBG_UTIL
void SalDisplay::DbgPrintDisplayEvent(const char *pComment, const XEvent *pEvent) const
{
static const char* const EventNames[] =
{
nullptr,
nullptr,
"KeyPress",
"KeyRelease",
"ButtonPress",
"ButtonRelease",
"MotionNotify",
"EnterNotify",
"LeaveNotify",
"FocusIn",
"FocusOut",
"KeymapNotify",
"Expose",
"GraphicsExpose",
"NoExpose",
"VisibilityNotify",
"CreateNotify",
"DestroyNotify",
"UnmapNotify",
"MapNotify",
"MapRequest",
"ReparentNotify",
"ConfigureNotify",
"ConfigureRequest",
"GravityNotify",
"ResizeRequest",
"CirculateNotify",
"CirculateRequest",
"PropertyNotify",
"SelectionClear",
"SelectionRequest",
"SelectionNotify",
"ColormapNotify",
"ClientMessage",
"MappingNotify"
};
if( pEvent->type <= MappingNotify )
{
SAL_INFO("vcl.app", "[" << pComment << "] "
<< EventNames[pEvent->type]
<< " s=" << pEvent->xany.send_event
<< " w=" << pEvent->xany.window);
switch( pEvent->type )
{
case KeyPress:
case KeyRelease:
SAL_INFO("vcl.app", "\t\ts=" << pEvent->xkey.state
<< " c=" << pEvent->xkey.keycode);
break;
case ButtonPress:
case ButtonRelease:
SAL_INFO("vcl.app", "\t\ts=" << pEvent->xbutton.state
<< " b=" << pEvent->xbutton.button
<< " x=" << pEvent->xbutton.x
<< " y=" << pEvent->xbutton.y
<< " rx=" << pEvent->xbutton.x_root
<< " ry=" << pEvent->xbutton.y_root);
break;
case MotionNotify:
SAL_INFO("vcl.app", "\t\ts=" << pEvent->xmotion.state
<< " x=" << pEvent->xmotion.x
<< " y=" << pEvent->xmotion.y);
break;
case EnterNotify:
case LeaveNotify:
SAL_INFO("vcl.app", "\t\tm=" << pEvent->xcrossing.mode
<< " f=" << pEvent->xcrossing.focus
<< " x=" << pEvent->xcrossing.x
<< " y=" << pEvent->xcrossing.y);
break;
case FocusIn:
case FocusOut:
SAL_INFO("vcl.app", "\t\tm=" << pEvent->xfocus.mode
<< " d=" << pEvent->xfocus.detail);
break;
case Expose:
case GraphicsExpose:
SAL_INFO("vcl.app", "\t\tc=" << pEvent->xexpose.count
<< " " << pEvent->xexpose.width
<< "*" << pEvent->xexpose.height
<< " " << pEvent->xexpose.x
<< "+" << pEvent->xexpose.y );
break;
case VisibilityNotify:
SAL_INFO("vcl.app", "\t\ts=" << pEvent->xvisibility.state);
break;
case CreateNotify:
case DestroyNotify:
break;
case MapNotify:
case UnmapNotify:
break;
case ReparentNotify:
SAL_INFO("vcl.app", "\t\tp=" << sal::static_int_cast< int >(
pEvent->xreparent.parent)
<< " x=" << pEvent->xreparent.x
<< " y=" << pEvent->xreparent.y );
break;
case ConfigureNotify:
SAL_INFO("vcl.app", "\t\tb=" << pEvent->xconfigure.border_width
<< " " << pEvent->xconfigure.width
<< "*" << pEvent->xconfigure.height
<< " " << pEvent->xconfigure.x
<< "+" << pEvent->xconfigure.y);
break;
case PropertyNotify:
SAL_INFO("vcl.app", "\t\ta=" << GetAtomName(
pDisp_, pEvent->xproperty.atom)
<< std::showbase << std::hex << std::uppercase
<< " (" << sal::static_int_cast< unsigned int >(
pEvent->xproperty.atom) << ").");
break;
case ColormapNotify:
SAL_INFO("vcl.app", "\t\tc=" << pEvent->xcolormap.colormap
<< " n=" << pEvent->xcolormap.c_new
<< " s=" << pEvent->xcolormap.state);
break;
case ClientMessage:
SAL_INFO("vcl.app", "\t\ta=" << GetAtomName(
pDisp_, pEvent->xclient.message_type)
<< std::showbase << std::hex << std::uppercase
<< " (" << sal::static_int_cast< unsigned int >(
pEvent->xclient.message_type) << ")"
<< std::dec
<< " f=" << pEvent->xclient.format
<< std::hex
<< " [" << pEvent->xclient.data.l[0]
<< "," << pEvent->xclient.data.l[1]
<< "," << pEvent->xclient.data.l[2]
<< "," << pEvent->xclient.data.l[3]
<< "," << pEvent->xclient.data.l[4]
<< "]");
break;
case MappingNotify:
SAL_INFO("vcl.app", "\t\tr="
<< (MappingModifier == pEvent->xmapping.request ?
"MappingModifier" :
(MappingKeyboard == pEvent->xmapping.request ?
"MappingKeyboard" : "MappingPointer"))
<< "d");
break;
}
}
else
SAL_INFO("vcl.app", "[" << pComment << "] "
<< pEvent->type
<< " s=" << pEvent->xany.send_event
<< " w=" << pEvent->xany.window);
}
void SalDisplay::PrintInfo() const
{
if( IsDisplay() )
{
SAL_INFO( "vcl", "Environment" );
SAL_INFO( "vcl", "\t$DISPLAY \t\"" << GetEnv( "DISPLAY" ) << "\"");
SAL_INFO( "vcl", "\t$SAL_VISUAL \t\"" << GetEnv( "SAL_VISUAL" ) << "\"");
SAL_INFO( "vcl", "\t$SAL_IGNOREXERRORS\t\"" << GetEnv( "SAL_IGNOREXERRORS" ) << "\"");
SAL_INFO( "vcl", "\t$SAL_PROPERTIES \t\"" << GetEnv( "SAL_PROPERTIES" ) << "\"");
SAL_INFO( "vcl", "\t$SAL_SYNCHRONIZE \t\"" << GetEnv( "SAL_SYNCHRONIZE" ) << "\"");
char sHostname[ 120 ];
gethostname (sHostname, 120 );
SAL_INFO( "vcl", "Client" );
SAL_INFO( "vcl", "\tHost \t\"" << sHostname << "\"");
SAL_INFO( "vcl", "Display" );
SAL_INFO( "vcl", "\tHost \t\"" << DisplayString(pDisp_) << "\"");
SAL_INFO( "vcl", "\tVendor (Release) \t\"" << ServerVendor(pDisp_) << " (" << VendorRelease(pDisp_) << ")\"");
SAL_INFO( "vcl", "\tProtocol \t" << ProtocolVersion(pDisp_) << "." << ProtocolRevision(pDisp_) );
SAL_INFO( "vcl", "\tScreen (count,def)\t" << m_nXDefaultScreen.getXScreen() << " (" << ScreenCount(pDisp_) << "," << DefaultScreen(pDisp_) << ")");
SAL_INFO( "vcl", "\tshift ctrl alt \t" << KeyStr( nShiftKeySym_ ) << " (0x" << std::hex << sal::static_int_cast< unsigned int >(nShiftKeySym_) << ") "
<< KeyStr( nCtrlKeySym_ ) << " (0x" << sal::static_int_cast< unsigned int >(nCtrlKeySym_) << ") "
<< KeyStr( nMod1KeySym_ ) << " (0x" << sal::static_int_cast< unsigned int >(nMod1KeySym_) << ")");
if( XExtendedMaxRequestSize(pDisp_) != 0 )
SAL_INFO( "vcl", "\tXMaxRequestSize \t" << XMaxRequestSize(pDisp_) * 4 << " " << XExtendedMaxRequestSize(pDisp_) * 4 << " [bytes]");
SAL_INFO( "vcl", "\tWMName \t" << getWMAdaptor()->getWindowManagerName() );
}
SAL_INFO( "vcl", "Screen" );
SAL_INFO( "vcl", "\tResolution/Size \t" << aResolution_.A() << "*" << aResolution_.B()
<< " " << m_aScreens[m_nXDefaultScreen.getXScreen()].m_aSize.Width() << "*" << m_aScreens[m_nXDefaultScreen.getXScreen()].m_aSize.Height()
<< " " << (std::hypot( DisplayWidthMM ( pDisp_, m_nXDefaultScreen.getXScreen() ),
DisplayHeightMM( pDisp_, m_nXDefaultScreen.getXScreen() ) ) / 25.4 ) << "\"" );
SAL_INFO( "vcl", "\tBlack&White \t" << GetColormap(m_nXDefaultScreen).GetBlackPixel() << " "
<< GetColormap(m_nXDefaultScreen).GetWhitePixel() );
SAL_INFO( "vcl", "\tRGB \t0x" << std::hex << GetVisual(m_nXDefaultScreen).red_mask
<< " 0x" << GetVisual(m_nXDefaultScreen).green_mask
<< " 0x" << GetVisual(m_nXDefaultScreen).blue_mask);
}
#endif
void SalDisplay::addXineramaScreenUnique( int i, tools::Long i_nX, tools::Long i_nY, tools::Long i_nWidth, tools::Long i_nHeight )
{
// see if any frame buffers are at the same coordinates
// this can happen with weird configuration e.g. on
// XFree86 and Clone displays
const size_t nScreens = m_aXineramaScreens.size();
for( size_t n = 0; n < nScreens; n++ )
{
if( m_aXineramaScreens[n].Left() == i_nX &&
m_aXineramaScreens[n].Top() == i_nY )
{
if( m_aXineramaScreens[n].GetWidth() < i_nWidth ||
m_aXineramaScreens[n].GetHeight() < i_nHeight )
{
m_aXineramaScreenIndexMap[i] = n;
m_aXineramaScreens[n].SetSize( AbsoluteScreenPixelSize( i_nWidth, i_nHeight ) );
}
return;
}
}
m_aXineramaScreenIndexMap[i] = m_aXineramaScreens.size();
m_aXineramaScreens.emplace_back( AbsoluteScreenPixelPoint( i_nX, i_nY ), AbsoluteScreenPixelSize( i_nWidth, i_nHeight ) );
}
void SalDisplay::InitXinerama()
{
if( m_aScreens.size() > 1 )
{
m_bXinerama = false;
return; // multiple screens mean no xinerama
}
if( !XineramaIsActive( pDisp_ ) )
return;
int nFramebuffers = 1;
XineramaScreenInfo* pScreens = XineramaQueryScreens( pDisp_, &nFramebuffers );
if( !pScreens )
return;
if( nFramebuffers > 1 )
{
m_aXineramaScreens = std::vector<AbsoluteScreenPixelRectangle>();
m_aXineramaScreenIndexMap = std::vector<int>(nFramebuffers);
for( int i = 0; i < nFramebuffers; i++ )
{
addXineramaScreenUnique( i, pScreens[i].x_org,
pScreens[i].y_org,
pScreens[i].width,
pScreens[i].height );
}
m_bXinerama = m_aXineramaScreens.size() > 1;
}
XFree( pScreens );
#if OSL_DEBUG_LEVEL > 1
if( m_bXinerama )
{
for (auto const& screen : m_aXineramaScreens)
SAL_INFO("vcl.app", "Xinerama screen: "
<< screen.GetWidth()
<< "x" << screen.GetHeight()
<< "+" << screen.Left()
<< "+" << screen.Top());
}
#endif
}
extern "C"
{
static Bool timestamp_predicate( Display*, XEvent* i_pEvent, XPointer i_pArg )
{
SalDisplay* pSalDisplay = reinterpret_cast<SalDisplay*>(i_pArg);
if( i_pEvent->type == PropertyNotify &&
i_pEvent->xproperty.window == pSalDisplay->GetDrawable( pSalDisplay->GetDefaultXScreen() ) &&
i_pEvent->xproperty.atom == pSalDisplay->getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT )
)
return True;
return False;
}
}
Time SalDisplay::GetEventTimeImpl( bool i_bAlwaysReget ) const
{
if( m_nLastUserEventTime == CurrentTime || i_bAlwaysReget )
{
// get current server time
unsigned char c = 0;
XEvent aEvent;
Atom nAtom = getWMAdaptor()->getAtom( WMAdaptor::SAL_GETTIMEEVENT );
XChangeProperty( GetDisplay(), GetDrawable( GetDefaultXScreen() ),
nAtom, nAtom, 8, PropModeReplace, &c, 1 );
XIfEvent( GetDisplay(), &aEvent, timestamp_predicate, reinterpret_cast<XPointer>(const_cast<SalDisplay *>(this)));
m_nLastUserEventTime = aEvent.xproperty.time;
}
return m_nLastUserEventTime;
}
SalVisual::SalVisual()
{
visual = nullptr;
}
SalVisual::SalVisual( const XVisualInfo* pXVI )
{
*static_cast<XVisualInfo*>(this) = *pXVI;
}
// Converts the order of bytes of a Pixel into bytes of a Color
// This is not reversible for the 6 XXXA
// Color is RGB (ABGR) a=0xFF000000, r=0xFF0000, g=0xFF00, b=0xFF
SalColormap::SalColormap( const SalDisplay *pDisplay, Colormap hColormap,
SalX11Screen nXScreen )
: m_pDisplay( pDisplay ),
m_hColormap( hColormap )
{
m_aVisual = m_pDisplay->GetVisual( nXScreen );
XColor aColor;
GetXPixel( aColor, 0x00, 0x00, 0x00 );
m_nBlackPixel = aColor.pixel;
GetXPixel( aColor, 0xFF, 0xFF, 0xFF );
m_nWhitePixel = aColor.pixel;
m_nUsed = 1 << m_aVisual.GetDepth();
if( m_aVisual.GetClass() != PseudoColor )
return;
int r, g, b;
// black, white, gray, ~gray = 4
GetXPixels( aColor, 0xC0, 0xC0, 0xC0 );
// light colors: 3 * 2 = 6
GetXPixels( aColor, 0x00, 0x00, 0xFF );
GetXPixels( aColor, 0x00, 0xFF, 0x00 );
GetXPixels( aColor, 0x00, 0xFF, 0xFF );
// standard colors: 7 * 2 = 14
GetXPixels( aColor, 0x00, 0x00, 0x80 );
GetXPixels( aColor, 0x00, 0x80, 0x00 );
GetXPixels( aColor, 0x00, 0x80, 0x80 );
GetXPixels( aColor, 0x80, 0x00, 0x00 );
GetXPixels( aColor, 0x80, 0x00, 0x80 );
GetXPixels( aColor, 0x80, 0x80, 0x00 );
GetXPixels( aColor, 0x80, 0x80, 0x80 );
GetXPixels( aColor, 0x00, 0xB8, 0xFF ); // Blue 7
// cube: 6*6*6 - 8 = 208
for( r = 0; r < 0x100; r += 0x33 ) // 0x33, 0x66, 0x99, 0xCC, 0xFF
for( g = 0; g < 0x100; g += 0x33 )
for( b = 0; b < 0x100; b += 0x33 )
GetXPixels( aColor, r, g, b );
// gray: 16 - 6 = 10
for( g = 0x11; g < 0xFF; g += 0x11 )
GetXPixels( aColor, g, g, g );
// green: 16 - 6 = 10
for( g = 0x11; g < 0xFF; g += 0x11 )
GetXPixels( aColor, 0, g, 0 );
// red: 16 - 6 = 10
for( r = 0x11; r < 0xFF; r += 0x11 )
GetXPixels( aColor, r, 0, 0 );
// blue: 16 - 6 = 10
for( b = 0x11; b < 0xFF; b += 0x11 )
GetXPixels( aColor, 0, 0, b );
}
// MonoChrome
SalColormap::SalColormap()
: m_pDisplay( vcl_sal::getSalDisplay(GetGenericUnixSalData()) ),
m_hColormap( None ),
m_nWhitePixel( 1 ),
m_nBlackPixel( 0 ),
m_nUsed( 2 )
{
m_aPalette = std::vector<Color>(m_nUsed);
m_aPalette[m_nBlackPixel] = COL_BLACK;
m_aPalette[m_nWhitePixel] = COL_WHITE;
}
// TrueColor
SalColormap::SalColormap( sal_uInt16 nDepth )
: m_pDisplay( vcl_sal::getSalDisplay(GetGenericUnixSalData()) ),
m_hColormap( None ),
m_nWhitePixel( (1 << nDepth) - 1 ),
m_nBlackPixel( 0x00000000 ),
m_nUsed( 1 << nDepth )
{
SalX11Screen nXScreen( vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDefaultXScreen() );
const SalVisual *pVisual = &m_pDisplay->GetVisual( nXScreen );
if( pVisual->GetClass() == TrueColor && pVisual->GetDepth() == nDepth )
m_aVisual = *pVisual;
else
{
XVisualInfo aVI;
if( !XMatchVisualInfo( m_pDisplay->GetDisplay(),
m_pDisplay->GetDefaultXScreen().getXScreen(),
nDepth,
TrueColor,
&aVI ) )
{
aVI.visual = new Visual;
aVI.visualid = VisualID(-1);
aVI.screen = -1;
aVI.depth = nDepth;
aVI.c_class = TrueColor;
if( 24 == nDepth ) // 888
{
aVI.red_mask = 0xFF0000;
aVI.green_mask = 0x00FF00;
aVI.blue_mask = 0x0000FF;
}
else if( 8 == nDepth ) // 332
{
aVI.red_mask = 0x0000E0;
aVI.green_mask = 0x00001C;
aVI.blue_mask = 0x000003;
}
else
{
aVI.red_mask = 0x000000;
aVI.green_mask = 0x000000;
aVI.blue_mask = 0x000000;
}
aVI.colormap_size = 0;
aVI.bits_per_rgb = 8;
aVI.visual->ext_data = nullptr;
aVI.visual->visualid = aVI.visualid;
aVI.visual->c_class = aVI.c_class;
aVI.visual->red_mask = aVI.red_mask;
aVI.visual->green_mask = aVI.green_mask;
aVI.visual->blue_mask = aVI.blue_mask;
aVI.visual->bits_per_rgb = aVI.bits_per_rgb;
aVI.visual->map_entries = aVI.colormap_size;
m_aVisual = SalVisual( &aVI );
m_aVisualOwnership.owner = true;
}
else
m_aVisual = SalVisual( &aVI );
}
}
SalColormap::~SalColormap()
{
if (m_aVisualOwnership.owner)
{
delete m_aVisual.visual;
}
}
inline bool SalColormap::GetXPixel( XColor &rColor,
int r,
int g,
int b ) const
{
rColor.red = r * 257;
rColor.green = g * 257;
rColor.blue = b * 257;
return XAllocColor( GetXDisplay(), m_hColormap, &rColor );
}
bool SalColormap::GetXPixels( XColor &rColor,
int r,
int g,
int b ) const
{
if( !GetXPixel( rColor, r, g, b ) )
return false;
if( rColor.pixel & 1 )
return true;
return GetXPixel( rColor, r^0xFF, g^0xFF, b^0xFF );
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V629 Consider inspecting the '1 << pSD->m_aVisual.GetDepth()' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type.
↑ V629 Consider inspecting the '1 << m_aVisual.GetDepth()' expression. Bit shifting of the 32-bit value with a subsequent expansion to the 64-bit type.
↑ V560 A part of conditional expression is always true: keysym >= 0xffbe.
↑ V560 A part of conditional expression is always true: keysym >= 0xffbe.
↑ V576 Incorrect format. Consider checking the third actual argument of the 'sscanf' function. A pointer to the signed long type is expected.
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1197, 1325
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1200, 1300, 1304
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1206, 1308, 1322
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1209, 1328
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1286, 1313, 1348
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1289, 1316, 1357
↑ V1037 Two or more case-branches perform the same actions. Check lines: 1292, 1319, 1354