/* -*- 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 #endif #include #include #include #include #include #include #include #include #include #include #include // 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(pObject->GetSystemData()); if ( ! XShapeQueryExtension( static_cast(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(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 (pSalDisp->GetVisual( nXScreen ).GetVisualId()) << ", of visual " << static_cast (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(nX); aRect.y = static_cast(nY); aRect.width = static_cast(nWidth); aRect.height= static_cast(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(maSystemChildData.pDisplay), aObjectParent, None); if ( maSecondary ) XDestroyWindow( static_cast(maSystemChildData.pDisplay), maSecondary ); if ( maPrimary ) XDestroyWindow( static_cast(maSystemChildData.pDisplay), maPrimary ); if ( maColormap ) XFreeColormap(static_cast(maSystemChildData.pDisplay), maColormap); XSync( static_cast(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(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(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(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(maSystemChildData.pDisplay), maPrimary, nX, nY, nWidth, nHeight ); XMoveResizeWindow( static_cast(maSystemChildData.pDisplay), maSecondary, 0, 0, nWidth, nHeight ); } } void X11SalObject::Show( bool bVisible ) { if (!maSystemChildData.GetWindowHandle(mpParent)) return; if ( bVisible ) { XMapWindow( static_cast(maSystemChildData.pDisplay), maSecondary ); XMapWindow( static_cast(maSystemChildData.pDisplay), maPrimary ); } else { XUnmapWindow( static_cast(maSystemChildData.pDisplay), maPrimary ); XUnmapWindow( static_cast(maSystemChildData.pDisplay), maSecondary ); } mbVisible = bVisible; } void X11SalObject::GrabFocus() { if( mbVisible ) XSetInputFocus( static_cast(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(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& rLeaveArgs, const css::uno::Sequence& 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: */