/* -*- 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 .
*/
#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
#endif
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/shape.h>
#include <vcl/keycodes.hxx>
#include <vcl/event.hxx>
#include <sal/log.hxx>
#include <unx/salinst.h>
#include <unx/saldisp.hxx>
#include <unx/salobj.h>
#include <salframe.hxx>
#include <salwtype.hxx>
// SalInstance member to create and destroy a SalObject
SalObject* X11SalInstance::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow )
{
return X11SalObject::CreateObject( pParent, pWindowData, bShow );
}
X11SalObject* X11SalObject::CreateObject( SalFrame* pParent, SystemWindowData* pWindowData, bool bShow )
{
int error_base, event_base;
X11SalObject* pObject = new X11SalObject();
SystemEnvData* pObjData = const_cast<SystemEnvData*>(pObject->GetSystemData());
if ( ! XShapeQueryExtension( static_cast<Display*>(pObjData->pDisplay),
&event_base, &error_base ) )
{
delete pObject;
return nullptr;
}
pObject->mpParent = pParent;
SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData());
const SystemEnvData* pEnv = pParent->GetSystemData();
Display* pDisp = pSalDisp->GetDisplay();
::Window aObjectParent = static_cast<::Window>(pEnv->GetWindowHandle(pParent));
pObject->maParentWin = aObjectParent;
// find out on which screen that window is
XWindowAttributes aParentAttr;
XGetWindowAttributes( pDisp, aObjectParent, &aParentAttr );
SalX11Screen nXScreen( XScreenNumberOfScreen( aParentAttr.screen ) );
Visual* pVisual = (pWindowData && pWindowData->pVisual) ?
static_cast<Visual*>(pWindowData->pVisual) :
pSalDisp->GetVisual( nXScreen ).GetVisual();
// get visual info
VisualID aVisID = XVisualIDFromVisual( pVisual );
XVisualInfo aTemplate;
aTemplate.visualid = aVisID;
int nVisuals = 0;
XVisualInfo* pInfo = XGetVisualInfo( pDisp, VisualIDMask, &aTemplate, &nVisuals );
// only one VisualInfo structure can match the visual id
SAL_WARN_IF( nVisuals != 1, "vcl", "match count for visual id is not 1" );
unsigned int nDepth = pInfo->depth;
XFree( pInfo );
XSetWindowAttributes aAttribs;
aAttribs.event_mask = StructureNotifyMask
| ButtonPressMask
| ButtonReleaseMask
| PointerMotionMask
| EnterWindowMask
| LeaveWindowMask
| FocusChangeMask
| ExposureMask
;
pObject->maPrimary =
XCreateSimpleWindow( pDisp,
aObjectParent,
0, 0,
1, 1, 0,
pSalDisp->GetColormap( nXScreen ).GetBlackPixel(),
pSalDisp->GetColormap( nXScreen ).GetWhitePixel()
);
if( aVisID == pSalDisp->GetVisual( nXScreen ).GetVisualId() )
{
pObject->maSecondary =
XCreateSimpleWindow( pDisp,
pObject->maPrimary,
0, 0,
1, 1, 0,
pSalDisp->GetColormap( nXScreen ).GetBlackPixel(),
pSalDisp->GetColormap( nXScreen ).GetWhitePixel()
);
}
else
{
#if OSL_DEBUG_LEVEL > 1
SAL_INFO("vcl.window", "visual id of vcl "
<< std::hex
<< static_cast<unsigned int>
(pSalDisp->GetVisual( nXScreen ).GetVisualId())
<< ", of visual "
<< static_cast<unsigned int>
(aVisID));
#endif
GetGenericUnixSalData()->ErrorTrapPush();
// create colormap for visual - there might not be one
pObject->maColormap = aAttribs.colormap = XCreateColormap(
pDisp,
pSalDisp->GetRootWindow( nXScreen ),
pVisual,
AllocNone );
pObject->maSecondary =
XCreateWindow( pDisp,
pSalDisp->GetRootWindow( nXScreen ),
0, 0,
1, 1, 0,
nDepth, InputOutput,
pVisual,
CWEventMask|CWColormap, &aAttribs );
XSync( pDisp, False );
if( GetGenericUnixSalData()->ErrorTrapPop( false ) )
{
pObject->maSecondary = None;
delete pObject;
return nullptr;
}
XReparentWindow( pDisp, pObject->maSecondary, pObject->maPrimary, 0, 0 );
}
GetGenericUnixSalData()->ErrorTrapPush();
if( bShow ) {
XMapWindow( pDisp, pObject->maSecondary );
XMapWindow( pDisp, pObject->maPrimary );
}
pObjData->pDisplay = pDisp;
pObjData->SetWindowHandle(pObject->maSecondary);
pObjData->pWidget = nullptr;
pObjData->pVisual = pVisual;
XSync(pDisp, False);
if( GetGenericUnixSalData()->ErrorTrapPop( false ) )
{
delete pObject;
return nullptr;
}
return pObject;
}
void X11SalInstance::DestroyObject( SalObject* pObject )
{
delete pObject;
}
// SalClipRegion is a member of SalObject
// definition of SalClipRegion my be found in vcl/inc/unx/salobj.h
SalClipRegion::SalClipRegion()
{
ClipRectangleList = nullptr;
numClipRectangles = 0;
maxClipRectangles = 0;
}
SalClipRegion::~SalClipRegion()
{
}
void
SalClipRegion::BeginSetClipRegion( sal_uInt32 nRects )
{
ClipRectangleList.reset( new XRectangle[nRects] );
numClipRectangles = 0;
maxClipRectangles = nRects;
}
void
SalClipRegion::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
{
if ( nWidth && nHeight && (numClipRectangles < maxClipRectangles) )
{
XRectangle& aRect = ClipRectangleList[numClipRectangles];
aRect.x = static_cast<short>(nX);
aRect.y = static_cast<short>(nY);
aRect.width = static_cast<unsigned short>(nWidth);
aRect.height= static_cast<unsigned short>(nHeight);
numClipRectangles++;
}
}
// SalObject Implementation
X11SalObject::X11SalObject()
: mpParent(nullptr)
, maParentWin(0)
, maPrimary(0)
, maSecondary(0)
, maColormap(0)
, mbVisible(false)
{
maSystemChildData.pDisplay = vcl_sal::getSalDisplay(GetGenericUnixSalData())->GetDisplay();
maSystemChildData.SetWindowHandle(None);
maSystemChildData.pSalFrame = nullptr;
maSystemChildData.pWidget = nullptr;
maSystemChildData.pVisual = nullptr;
maSystemChildData.aShellWindow = 0;
maSystemChildData.toolkit = SystemEnvData::Toolkit::Gen;
maSystemChildData.platform = SystemEnvData::Platform::Xcb;
std::list< SalObject* >& rObjects = vcl_sal::getSalDisplay(GetGenericUnixSalData())->getSalObjects();
rObjects.push_back( this );
}
X11SalObject::~X11SalObject()
{
std::list< SalObject* >& rObjects = vcl_sal::getSalDisplay(GetGenericUnixSalData())->getSalObjects();
rObjects.remove( this );
GetGenericUnixSalData()->ErrorTrapPush();
::Window aObjectParent = maParentWin;
XSetWindowBackgroundPixmap(static_cast<Display*>(maSystemChildData.pDisplay), aObjectParent, None);
if ( maSecondary )
XDestroyWindow( static_cast<Display*>(maSystemChildData.pDisplay), maSecondary );
if ( maPrimary )
XDestroyWindow( static_cast<Display*>(maSystemChildData.pDisplay), maPrimary );
if ( maColormap )
XFreeColormap(static_cast<Display*>(maSystemChildData.pDisplay), maColormap);
XSync( static_cast<Display*>(maSystemChildData.pDisplay), False );
GetGenericUnixSalData()->ErrorTrapPop();
}
void
X11SalObject::ResetClipRegion()
{
maClipRegion.ResetClipRegion();
const int dest_kind = ShapeBounding;
const int op = ShapeSet;
const int ordering = YSorted;
XWindowAttributes win_attrib;
XRectangle win_size;
::Window aShapeWindow = maPrimary;
XGetWindowAttributes ( static_cast<Display*>(maSystemChildData.pDisplay),
aShapeWindow,
&win_attrib );
win_size.x = 0;
win_size.y = 0;
win_size.width = win_attrib.width;
win_size.height = win_attrib.height;
XShapeCombineRectangles ( static_cast<Display*>(maSystemChildData.pDisplay),
aShapeWindow,
dest_kind,
0, 0, // x_off, y_off
&win_size, // list of rectangles
1, // number of rectangles
op, ordering );
}
void
X11SalObject::BeginSetClipRegion( sal_uInt32 nRectCount )
{
maClipRegion.BeginSetClipRegion ( nRectCount );
}
void
X11SalObject::UnionClipRegion( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
{
maClipRegion.UnionClipRegion ( nX, nY, nWidth, nHeight );
}
void
X11SalObject::EndSetClipRegion()
{
XRectangle *pRectangles = maClipRegion.EndSetClipRegion ();
const int nRectangles = maClipRegion.GetRectangleCount();
::Window aShapeWindow = maPrimary;
XShapeCombineRectangles ( static_cast<Display*>(maSystemChildData.pDisplay),
aShapeWindow,
ShapeBounding,
0, 0, // x_off, y_off
pRectangles,
nRectangles,
ShapeSet, YSorted );
}
void
X11SalObject::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight )
{
if ( maPrimary && maSecondary && nWidth && nHeight )
{
XMoveResizeWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maPrimary,
nX, nY, nWidth, nHeight );
XMoveResizeWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maSecondary,
0, 0, nWidth, nHeight );
}
}
void
X11SalObject::Show( bool bVisible )
{
if (!maSystemChildData.GetWindowHandle(mpParent))
return;
if ( bVisible ) {
XMapWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maSecondary );
XMapWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maPrimary );
} else {
XUnmapWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maPrimary );
XUnmapWindow( static_cast<Display*>(maSystemChildData.pDisplay),
maSecondary );
}
mbVisible = bVisible;
}
void X11SalObject::GrabFocus()
{
if( mbVisible )
XSetInputFocus( static_cast<Display*>(maSystemChildData.pDisplay),
maSystemChildData.GetWindowHandle(mpParent),
RevertToNone,
CurrentTime );
}
const SystemEnvData* X11SalObject::GetSystemData() const
{
return &maSystemChildData;
}
static sal_uInt16 sal_GetCode( int state )
{
sal_uInt16 nCode = 0;
if( state & Button1Mask )
nCode |= MOUSE_LEFT;
if( state & Button2Mask )
nCode |= MOUSE_MIDDLE;
if( state & Button3Mask )
nCode |= MOUSE_RIGHT;
if( state & ShiftMask )
nCode |= KEY_SHIFT;
if( state & ControlMask )
nCode |= KEY_MOD1;
if( state & Mod1Mask )
nCode |= KEY_MOD2;
if( state & Mod3Mask )
nCode |= KEY_MOD3;
return nCode;
}
bool X11SalObject::Dispatch( XEvent* pEvent )
{
std::list< SalObject* >& rObjects = vcl_sal::getSalDisplay(GetGenericUnixSalData())->getSalObjects();
for (auto const& elem : rObjects)
{
X11SalObject* pObject = static_cast<X11SalObject*>(elem);
if( pEvent->xany.window == pObject->maPrimary ||
pEvent->xany.window == pObject->maSecondary )
{
if( pObject->IsMouseTransparent() && (
pEvent->type == ButtonPress ||
pEvent->type == ButtonRelease ||
pEvent->type == EnterNotify ||
pEvent->type == LeaveNotify ||
pEvent->type == MotionNotify
)
)
{
SalMouseEvent aEvt;
int dest_x, dest_y;
::Window aChild = None;
XTranslateCoordinates( pEvent->xbutton.display,
pEvent->xbutton.root,
pObject->maParentWin,
pEvent->xbutton.x_root,
pEvent->xbutton.y_root,
&dest_x, &dest_y,
&aChild );
aEvt.mnX = dest_x;
aEvt.mnY = dest_y;
aEvt.mnTime = pEvent->xbutton.time;
aEvt.mnCode = sal_GetCode( pEvent->xbutton.state );
aEvt.mnButton = 0;
SalEvent nEvent = SalEvent::NONE;
if( pEvent->type == ButtonPress ||
pEvent->type == ButtonRelease )
{
switch( pEvent->xbutton.button )
{
case Button1: aEvt.mnButton = MOUSE_LEFT;break;
case Button2: aEvt.mnButton = MOUSE_MIDDLE;break;
case Button3: aEvt.mnButton = MOUSE_RIGHT;break;
}
nEvent = (pEvent->type == ButtonPress) ?
SalEvent::MouseButtonDown :
SalEvent::MouseButtonUp;
}
else if( pEvent->type == EnterNotify )
nEvent = SalEvent::MouseLeave;
else
nEvent = SalEvent::MouseMove;
pObject->mpParent->CallCallback( nEvent, &aEvt );
}
else
{
switch( pEvent->type )
{
case UnmapNotify:
pObject->mbVisible = false;
return true;
case MapNotify:
pObject->mbVisible = true;
return true;
case ButtonPress:
pObject->CallCallback( SalObjEvent::ToTop );
return true;
case FocusIn:
pObject->CallCallback( SalObjEvent::GetFocus );
return true;
case FocusOut:
pObject->CallCallback( SalObjEvent::LoseFocus );
return true;
default: break;
}
}
return false;
}
}
return false;
}
void X11SalObject::SetLeaveEnterBackgrounds(const css::uno::Sequence<css::uno::Any>& rLeaveArgs, const css::uno::Sequence<css::uno::Any>& rEnterArgs)
{
SalDisplay* pSalDisp = vcl_sal::getSalDisplay(GetGenericUnixSalData());
Display* pDisp = pSalDisp->GetDisplay();
::Window aObjectParent = maParentWin;
bool bFreePixmap = false;
Pixmap aPixmap = None;
if (rEnterArgs.getLength() == 2)
{
rEnterArgs[0] >>= bFreePixmap;
sal_Int64 pixmapHandle = None;
rEnterArgs[1] >>= pixmapHandle;
aPixmap = pixmapHandle;
}
XSetWindowBackgroundPixmap(pDisp, aObjectParent, aPixmap);
if (bFreePixmap)
XFreePixmap(pDisp, aPixmap);
bFreePixmap = false;
aPixmap = None;
if (rLeaveArgs.getLength() == 2)
{
rLeaveArgs[0] >>= bFreePixmap;
sal_Int64 pixmapHandle = None;
rLeaveArgs[1] >>= pixmapHandle;
aPixmap = pixmapHandle;
}
XSetWindowBackgroundPixmap(pDisp, maSecondary, aPixmap);
if (bFreePixmap)
XFreePixmap(pDisp, aPixmap);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression 'bFreePixmap' is always false.
↑ V547 Expression 'bFreePixmap' is always false.