Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/unx/generic/window/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 134 kB image not shown  

Quelle  salframe.cxx   Sprache: C

 
/* -*- 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 <string_view>
#include <stdio.h>
#include <stdlib.h>

#include <tools/debug.hxx>

#include <vcl/event.hxx>
#include <vcl/toolkit/floatwin.hxx>
#include <vcl/keycodes.hxx>
#include <vcl/settings.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/opengl/OpenGLContext.hxx>
#include <vcl/BitmapTools.hxx>

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/extensions/shape.h>

#include <headless/BitmapHelper.hxx>
#include <headless/svpbmp.hxx>
#include <unx/saldisp.hxx>
#include <unx/salgdi.h>
#include <unx/salframe.h>
#include <unx/wmadaptor.hxx>
#include <unx/i18n_ic.hxx>
#include <unx/i18n_keysym.hxx>
#include <opengl/zone.hxx>

#include <unx/gensys.h>
#include <window.h>

#include <sal/macros.h>
#include <sal/log.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/string_view.hxx>
#include <com/sun/star/uno/Exception.hpp>

#include <salinst.hxx>
#include <svdata.hxx>
#include <bitmaps.hlst>

#include <cairo-xlib.h>

#include <optional>

#include <algorithm>

#ifndef Button6
define Button6 6
#endif
#ifndef Button7
define Button7 7
#endif

using namespace vcl_sal;

constexpr auto CLIENT_EVENTS = StructureNotifyMask
                                | SubstructureNotifyMask
                                | KeyPressMask
                                | KeyReleaseMask
                                | ButtonPressMask
                                | ButtonReleaseMask
                                | PointerMotionMask
                                | EnterWindowMask
                                | LeaveWindowMask
                                | FocusChangeMask
                                | ExposureMask
                                | VisibilityChangeMask
                                | PropertyChangeMask
                                | ColormapChangeMask;

static ::Window  hPresentationWindow = None, hPresFocusWindow = None;
static ::std::list< ::Window > aPresentationReparentList;
static int          nVisibleFloats      = 0;

static void doReparentPresentationDialogues( SalDisplay const * pDisplay )
{
    GetGenericUnixSalData()->ErrorTrapPush();
    for (auto const& elem : aPresentationReparentList)
    {
        int x, y;
        ::Window aRoot, aChild;
        unsigned int w, h, bw, d;
        XGetGeometry( pDisplay->GetDisplay(),
                      elem,
                      &aRoot,
                      &x, &y, &w, &h, &bw, &d );
        XTranslateCoordinates( pDisplay->GetDisplay(),
                               hPresentationWindow,
                               aRoot,
                               x, y,
                               &x, &y,
                               &aChild );
        XReparentWindow( pDisplay->GetDisplay(),
                         elem,
                         aRoot,
                         x, y );
    }
    aPresentationReparentList.clear();
    if( hPresFocusWindow )
        XSetInputFocus( pDisplay->GetDisplay(), hPresFocusWindow, PointerRoot, CurrentTime );
    XSync( pDisplay->GetDisplay(), False );
    GetGenericUnixSalData()->ErrorTrapPop();
}

bool X11SalFrame::IsOverrideRedirect() const
{
    return
        ((nStyle_ & SalFrameStyleFlags::INTRO) && !pDisplay_->getWMAdaptor()->supportsSplash())
        ||
        (!( nStyle_ & ~SalFrameStyleFlags::DEFAULT ) && !pDisplay_->getWMAdaptor()->supportsFullScreen())
        ;
}

bool X11SalFrame::IsFloatGrabWindow() const
{
    static const char* pDisableGrab = getenv( "SAL_DISABLE_FLOATGRAB" );

    return
        ( ( !pDisableGrab || !*pDisableGrab ) &&
          (
           (nStyle_ & SalFrameStyleFlags::FLOAT)    &&
           ! (nStyle_ & SalFrameStyleFlags::TOOLTIP)    &&
           ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION)
           )
          );
}

void X11SalFrame::setXEmbedInfo()
{
    if( !m_bXEmbed )
        return;

    tools::Long aInfo[2];
    aInfo[0] = 1; // XEMBED protocol version
    aInfo[1] = (bMapped_ ? 1 : 0); // XEMBED_MAPPED
    XChangeProperty( pDisplay_->GetDisplay(),
                     mhWindow,
                     pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
                     pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED_INFO ),
                     32,
                     PropModeReplace,
                     reinterpret_cast<unsigned char*>(aInfo),
                     SAL_N_ELEMENTS(aInfo) );
}

void X11SalFrame::askForXEmbedFocus( sal_Int32 i_nTimeCode )
{
    XEvent aEvent;

    memset( &aEvent, 0, sizeof(aEvent) );
    aEvent.xclient.window = mhForeignParent;
    aEvent.xclient.type = ClientMessage;
    aEvent.xclient.message_type = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::XEMBED );
    aEvent.xclient.format = 32;
    aEvent.xclient.data.l[0] = i_nTimeCode ? i_nTimeCode : CurrentTime;
    aEvent.xclient.data.l[1] = 3; // XEMBED_REQUEST_FOCUS
    aEvent.xclient.data.l[2] = 0;
    aEvent.xclient.data.l[3] = 0;
    aEvent.xclient.data.l[4] = 0;

    GetGenericUnixSalData()->ErrorTrapPush();
    XSendEvent( pDisplay_->GetDisplay(),
                mhForeignParent,
                False, NoEventMask, &aEvent );
    XSync( pDisplay_->GetDisplay(), False );
    GetGenericUnixSalData()->ErrorTrapPop();
}

typedef std::vector< unsigned long > NetWmIconData;

namespace
{
    constexpr OUString SV_ICON_SIZE48[] =
    {
        MAINAPP_48_8,
        MAINAPP_48_8,
        ODT_48_8,
        OTT_48_8,
        ODS_48_8,
        OTS_48_8,
        ODG_48_8,
        MAINAPP_48_8,
        ODP_48_8,
        MAINAPP_48_8,
        ODM_48_8,
        MAINAPP_48_8,
        ODB_48_8,
        ODF_48_8
    };

    constexpr OUString SV_ICON_SIZE32[] =
    {
        MAINAPP_32_8,
        MAINAPP_32_8,
        ODT_32_8,
        OTT_32_8,
        ODS_32_8,
        OTS_32_8,
        ODG_32_8,
        MAINAPP_32_8,
        ODP_32_8,
        MAINAPP_32_8,
        ODM_32_8,
        MAINAPP_32_8,
        ODB_32_8,
        ODF_32_8
    };

    constexpr OUString SV_ICON_SIZE16[] =
    {
        MAINAPP_16_8,
        MAINAPP_16_8,
        ODT_16_8,
        OTT_16_8,
        ODS_16_8,
        OTS_16_8,
        ODG_16_8,
        MAINAPP_16_8,
        ODP_16_8,
        MAINAPP_16_8,
        ODM_16_8,
        MAINAPP_16_8,
        ODB_16_8,
        ODF_16_8
    };
}

static void CreateNetWmAppIcon( sal_uInt16 nIcon, NetWmIconData& netwm_icon )
{
    const int sizes[ 3 ] = { 48, 32, 16 };
    netwm_icon.resize( 48 * 48 + 32 * 32 + 16 * 16 + 3 * 2 );
    int pos = 0;
    for(int size : sizes)
    {
        OUString sIcon;
        if( size >= 48 )
            sIcon = SV_ICON_SIZE48[nIcon];
        else if( size >= 32 )
            sIcon = SV_ICON_SIZE32[nIcon];
        else
            sIcon = SV_ICON_SIZE16[nIcon];

        BitmapEx aIcon = vcl::bitmap::loadFromName(sIcon, ImageLoadFlags::IgnoreScalingFactor);

        if( aIcon.IsEmpty())
            continue;
        vcl::bitmap::convertBitmap32To24Plus8(aIcon, aIcon);
        Bitmap icon = aIcon.GetBitmap();
        AlphaMask mask = aIcon.GetAlphaMask();
        BitmapScopedReadAccess iconData(icon);
        BitmapScopedReadAccess maskData(mask);
        netwm_icon[ pos++ ] = size; // width
        netwm_icon[ pos++ ] = size; // height
        forint y = 0; y < size; ++y )
            forint x = 0; x < size; ++x )
            {
                BitmapColor col = iconData->GetColor( y, x );
                BitmapColor alpha = maskData->GetColor( y, x );
                netwm_icon[ pos++ ] = (((( 255 - alpha.GetBlue()) * 256U ) + col.GetRed()) * 256 + col.GetGreen()) * 256 + col.GetBlue();
            }
    }
    netwm_icon.resize( pos );
}

void X11SalFrame::Init( SalFrameStyleFlags nSalFrameStyle, SalX11Screen nXScreen, SystemParentData const * pParentData, bool bUseGeometry )
{
    if( nXScreen.getXScreen() >= GetDisplay()->GetXScreenCount() )
        nXScreen = GetDisplay()->GetDefaultXScreen();
    if( mpParent )
        nXScreen = mpParent->m_nXScreen;

    m_nXScreen  = nXScreen;
    nStyle_     = nSalFrameStyle;
    XWMHints Hints;
    Hints.flags = InputHint;
    Hints.input = (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION) ? False : True;
    NetWmIconData netwm_icon;

    int x = 0, y = 0;
    unsigned int w = 500, h = 500;
    XSetWindowAttributes Attributes;

    int nAttrMask =   CWBorderPixel
                    | CWBackPixmap
                    | CWColormap
                    | CWOverrideRedirect
                    | CWEventMask
                    ;
    Attributes.border_pixel             = 0;
    Attributes.background_pixmap        = None;
    Attributes.colormap                 = GetDisplay()->GetColormap( m_nXScreen ).GetXColormap();
    Attributes.override_redirect        = False;
    Attributes.event_mask               = CLIENT_EVENTS;

    const SalVisual& rVis = GetDisplay()->GetVisual( m_nXScreen );
    ::Window aFrameParent = pParentData ? pParentData->aWindow : GetDisplay()->GetRootWindow( m_nXScreen );
    ::Window aClientLeader = None;

    if( bUseGeometry )
    {
        x = maGeometry.x();
        y = maGeometry.y();
        w = maGeometry.width();
        h = maGeometry.height();
    }

    if( (nSalFrameStyle & SalFrameStyleFlags::FLOAT) &&
        ! (nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION)
        )
    {
        if( nShowState_ == X11ShowState::Unknown )
        {
            w = 10;
            h = 10;
        }
        Attributes.override_redirect = True;
    }
    else if( nSalFrameStyle & SalFrameStyleFlags::SYSTEMCHILD )
    {
        SAL_WARN_IF( !mpParent, "vcl""SalFrameStyleFlags::SYSTEMCHILD window without parent" );
        if( mpParent )
        {
            aFrameParent = mpParent->mhWindow;
            // FIXME: since with SalFrameStyleFlags::SYSTEMCHILD
            // multiple X11SalFrame objects can have the same shell window
            // dispatching events in saldisp.cxx is unclear (the first frame)
            // wins. HTH this correctly is unclear yet
            // for the time being, treat set the shell window to own window
            // like for a normal frame
            // mhShellWindow = mpParent->GetShellWindow();
        }
    }
    else if( pParentData )
    {
        // plugin parent may be killed unexpectedly by plugging
        // process; start permanently ignoring X errors...
        GetGenericUnixSalData()->ErrorTrapPush();

        nStyle_ |= SalFrameStyleFlags::PLUG;
        Attributes.override_redirect = True;
        if( pParentData->nSize >= sizeof(SystemParentData) )
            m_bXEmbed = pParentData->bXEmbedSupport;

        int x_ret, y_ret;
        unsigned int bw, d;
        ::Window aRoot, aParent;

        XGetGeometry( GetXDisplay(), pParentData->aWindow,
                      &aRoot, &x_ret, &y_ret, &w, &h, &bw, &d );
        mhForeignParent = pParentData->aWindow;

        mhShellWindow = aParent = mhForeignParent;
        ::Window* pChildren;
        unsigned int nChildren;
        bool bBreak = false;
        do
        {
            XQueryTree( GetDisplay()->GetDisplay(), mhShellWindow,
                        &aRoot, &aParent, &pChildren, &nChildren );
            XFree( pChildren );
            if( aParent != aRoot )
                mhShellWindow = aParent;
            int nCount = 0;
            Atom* pProps = XListProperties( GetDisplay()->GetDisplay(),
                                            mhShellWindow,
                                            &nCount );
            forint i = 0; i < nCount && ! bBreak; ++i )
                bBreak = (pProps[i] == XA_WM_HINTS);
            if( pProps )
                XFree( pProps );
        } while( aParent != aRoot && ! bBreak );

        // check if this is really one of our own frames
        // do not change the input mask in that case
        bool bIsReallyOurFrame = false;
        for (auto pSalFrame : GetDisplay()->getFrames() )
            if ( static_cast<const X11SalFrame*>( pSalFrame )->GetWindow() == mhForeignParent )
            {
                bIsReallyOurFrame = true;
                break;
            }
        if (!bIsReallyOurFrame)
        {
            XSelectInput( GetDisplay()->GetDisplay(), mhForeignParent, StructureNotifyMask | FocusChangeMask );
            XSelectInput( GetDisplay()->GetDisplay(), mhShellWindow, StructureNotifyMask | FocusChangeMask );
        }
    }
    else
    {
        if( ! bUseGeometry )
        {
            Size aScreenSize( GetDisplay()->getDataForScreen( m_nXScreen ).m_aSize );
            w = aScreenSize.Width();
            h = aScreenSize.Height();
            if( nSalFrameStyle & SalFrameStyleFlags::SIZEABLE &&
                nSalFrameStyle & SalFrameStyleFlags::MOVEABLE )
            {
                Size aBestFitSize(bestmaxFrameSizeForScreenSize(aScreenSize));
                w = aBestFitSize.Width();
                h = aBestFitSize.Height();
            }
            if( ! mpParent )
            {
                // find the last document window (if any)
                const X11SalFrame* pFrame = nullptr;
                bool bIsDocumentWindow = false;
                for (auto pSalFrame : GetDisplay()->getFrames() )
                {
                    pFrame = static_castconst X11SalFrame* >( pSalFrame );
                    if( !pFrame->mpParent
                        && !pFrame->mbFullScreen
                        && ( pFrame->nStyle_ & SalFrameStyleFlags::SIZEABLE )
                        && pFrame->GetUnmirroredGeometry().width()
                        && pFrame->GetUnmirroredGeometry().height() )
                    {
                        bIsDocumentWindow = true;
                        break;
                    }
                }

                if( bIsDocumentWindow )
                {
                    // set a document position and size
                    // the first frame gets positioned by the window manager
                    const SalFrameGeometry aGeom( pFrame->GetUnmirroredGeometry() );
                    x = aGeom.x();
                    y = aGeom.y();
                    if( x+static_cast<int>(w)+40 <= static_cast<int>(aScreenSize.Width()) &&
                        y+static_cast<int>(h)+40 <= static_cast<int>(aScreenSize.Height())
                        )
                    {
                        y += 40;
                        x += 40;
                    }
                    else
                    {
                        x = 10; // leave some space for decoration
                        y = 20;
                    }
                }
                else if( GetDisplay()->IsXinerama() )
                {
                    // place frame on same screen as mouse pointer
                    ::Window aRoot, aChild;
                    int root_x = 0, root_y = 0, lx, ly;
                    unsigned int mask;
                    XQueryPointer( GetXDisplay(),
                                   GetDisplay()->GetRootWindow( m_nXScreen ),
                                   &aRoot, &aChild,
                                   &root_x, &root_y, &lx, &ly, &mask );
                    const std::vector< AbsoluteScreenPixelRectangle >& rScreens = GetDisplay()->GetXineramaScreens();
                    for(const auto & rScreen : rScreens)
                        if( rScreen.Contains( AbsoluteScreenPixelPoint( root_x, root_y ) ) )
                        {
                            x = rScreen.Left();
                            y = rScreen.Top();
                            break;
                        }
                }
            }
        }
        Attributes.win_gravity = pDisplay_->getWMAdaptor()->getInitWinGravity();
        nAttrMask |= CWWinGravity;
        if( mpParent )
        {
            Attributes.save_under = True;
            nAttrMask |= CWSaveUnder;
        }
        if( IsOverrideRedirect() )
            Attributes.override_redirect = True;
        // default icon
        if( !(nStyle_ & SalFrameStyleFlags::INTRO) && !(nStyle_ & SalFrameStyleFlags::NOICON))
        {
            try
            {
                CreateNetWmAppIcon( mnIconID != SV_ICON_ID_OFFICE ? mnIconID :
                                    (mpParent ? mpParent->mnIconID : SV_ICON_ID_OFFICE), netwm_icon );
            }
            catch( css::uno::Exception& )
            {
                // can happen - no ucb during early startup
            }
        }

        // find the top level frame of the transience hierarchy
        X11SalFrame* pFrame = this;
        while( pFrame->mpParent )
            pFrame = pFrame->mpParent;
        if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
        {
            // if the top level window is a plugin window,
            // then we should place us in the same window group as
            // the parent application (or none if there is no window group
            // hint in the parent).
            if( pFrame->GetShellWindow() )
            {
                XWMHints* pWMHints = XGetWMHints( pDisplay_->GetDisplay(),
                    pFrame->GetShellWindow() );
                if( pWMHints )
                {
                    if( pWMHints->flags & WindowGroupHint )
                    {
                        Hints.flags |= WindowGroupHint;
                        Hints.window_group = pWMHints->window_group;
                    }
                    XFree( pWMHints );
                }
            }
        }
        else
        {
            Hints.flags         |= WindowGroupHint;
            Hints.window_group  = pFrame->GetShellWindow();
            // note: for a normal document window this will produce None
            // as the window is not yet created and the shell window is
            // initialized to None. This must be corrected after window creation.
            aClientLeader = GetDisplay()->GetDrawable( m_nXScreen );
        }
    }

    nShowState_                 = X11ShowState::Unknown;
    bViewable_                  = true;
    bMapped_                    = false;
    nVisibility_                = VisibilityFullyObscured;
    mhWindow = XCreateWindow( GetXDisplay(),
                              aFrameParent,
                              x, y,
                              w, h,
                              0,
                              rVis.GetDepth(),
                              InputOutput,
                              rVis.GetVisual(),
                              nAttrMask,
                              &Attributes );
    mpSurface = cairo_xlib_surface_create(GetXDisplay(), mhWindow,
                                          rVis.GetVisual(),
                                          w, h);

    // FIXME: see above: fake shell window for now to own window
    if( pParentData == nullptr )
    {
        mhShellWindow = mhWindow;
    }

    // correct window group if necessary
    if( (Hints.flags & WindowGroupHint) == WindowGroupHint )
    {
        if( Hints.window_group == None )
            Hints.window_group = GetShellWindow();
    }

    maGeometry.setPosSize({ x, y }, { static_cast<tools::Long>(w), static_cast<tools::Long>(h) });
    updateScreenNumber();

    XSync( GetXDisplay(), False );
    setXEmbedInfo();

    Time nUserTime = (nStyle_ & (SalFrameStyleFlags::OWNERDRAWDECORATION | SalFrameStyleFlags::TOOLWINDOW) ) == SalFrameStyleFlags::NONE ?
        pDisplay_->GetLastUserEventTime() : 0;
    pDisplay_->getWMAdaptor()->setUserTime( this, nUserTime );

    if( ! pParentData && ! IsChildWindow() && ! Attributes.override_redirect )
    {
        XSetWMHints( GetXDisplay(), mhWindow, &Hints );
        // WM Protocols && internals
        Atom a[3];
        int  n = 0;
        a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_DELETE_WINDOW );

// LibreOffice advertises NET_WM_PING atom, so mutter rightfully warns of an unresponsive application during debugging.
// Hack that out unconditionally for debug builds, as per https://bugzilla.redhat.com/show_bug.cgi?id=981149
// upstream refuses to make this configurable in any way.
// NOTE: You need to use the 'gen' backend for this to work (SAL_USE_VCLPLUGIN=gen)
#if OSL_DEBUG_LEVEL < 1
        if( pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING ) )
            a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_PING );
#endif

        if( nSalFrameStyle & SalFrameStyleFlags::OWNERDRAWDECORATION )
            a[n++] = pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_TAKE_FOCUS );
        XSetWMProtocols( GetXDisplay(), GetShellWindow(), a, n );

        // force wm class hint
        mnExtStyle = ~0;
        if (mpParent)
            m_sWMClass = mpParent->m_sWMClass;
        SetExtendedFrameStyle( 0 );

        XSizeHints* pHints = XAllocSizeHints();
        pHints->flags       = PWinGravity | PPosition;
        pHints->win_gravity = GetDisplay()->getWMAdaptor()->getPositionWinGravity();
        pHints->x           = 0;
        pHints->y           = 0;
        if( mbFullScreen )
        {
            pHints->flags |= PMaxSize | PMinSize;
            pHints->max_width = w+100;
            pHints->max_height = h+100;
            pHints->min_width  = w;
            pHints->min_height = h;
        }
        XSetWMNormalHints( GetXDisplay(),
                           GetShellWindow(),
                           pHints );
        XFree (pHints);

        // set PID and WM_CLIENT_MACHINE
        pDisplay_->getWMAdaptor()->setClientMachine( this );
        pDisplay_->getWMAdaptor()->setPID( this );

        // set client leader
        if( aClientLeader )
        {
            XChangeProperty( GetXDisplay(),
                             mhWindow,
                             pDisplay_->getWMAdaptor()->getAtom( WMAdaptor::WM_CLIENT_LEADER),
                             XA_WINDOW,
                             32,
                             PropModeReplace,
                             reinterpret_cast<unsigned char*>(&aClientLeader),
                             1
                             );
        }
#define DECOFLAGS (SalFrameStyleFlags::MOVEABLE | SalFrameStyleFlags::SIZEABLE | SalFrameStyleFlags::CLOSEABLE)
        int nDecoFlags = WMAdaptor::decoration_All;
        if (m_bIsPartialFullScreen || (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION))
            nDecoFlags = 0;
        else if( (nStyle_ & DECOFLAGS ) != DECOFLAGS || (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
        {
            if( nStyle_ & DECOFLAGS )
                // if any decoration, then show a border
                nDecoFlags = WMAdaptor::decoration_Border;
            else
                nDecoFlags = 0;

            if( ! mpParent && (nStyle_ & DECOFLAGS) )
                // don't add a min button if window should be decorationless
                nDecoFlags |= WMAdaptor::decoration_MinimizeBtn;
            if( nStyle_ & SalFrameStyleFlags::CLOSEABLE )
                nDecoFlags |= WMAdaptor::decoration_CloseBtn;
            if( nStyle_ & SalFrameStyleFlags::SIZEABLE )
            {
                nDecoFlags |= WMAdaptor::decoration_Resize;
                if( ! (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
                    nDecoFlags |= WMAdaptor::decoration_MaximizeBtn;
            }
            if( nStyle_ & SalFrameStyleFlags::MOVEABLE )
                nDecoFlags |= WMAdaptor::decoration_Title;
        }

        WMWindowType eType = WMWindowType::Normal;
        if( nStyle_ & SalFrameStyleFlags::INTRO )
            eType = WMWindowType::Splash;
        if( (nStyle_ & SalFrameStyleFlags::DIALOG) && hPresentationWindow == None )
            eType = WMWindowType::ModelessDialogue;
        if( nStyle_ & SalFrameStyleFlags::TOOLWINDOW )
            eType = WMWindowType::Utility;
        if( nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION )
            eType = WMWindowType::Toolbar;
        if (m_bIsPartialFullScreen && GetDisplay()->getWMAdaptor()->isLegacyPartialFullscreen())
            eType = WMWindowType::Dock;

        GetDisplay()->getWMAdaptor()->
            setFrameTypeAndDecoration( this,
                                       eType,
                                       nDecoFlags,
                                       hPresentationWindow ? nullptr : mpParent );

        if (!m_bIsPartialFullScreen && (nStyle_ & (SalFrameStyleFlags::DEFAULT |
                        SalFrameStyleFlags::OWNERDRAWDECORATION|
                        SalFrameStyleFlags::FLOAT |
                        SalFrameStyleFlags::INTRO))
             == SalFrameStyleFlags::DEFAULT )
            pDisplay_->getWMAdaptor()->maximizeFrame( this );

        if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
            XChangeProperty( GetXDisplay(), mhWindow,
                GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
                XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
    }

    m_nWorkArea = GetDisplay()->getWMAdaptor()->getCurrentWorkArea();

    // Pointer
    SetPointer( PointerStyle::Arrow );
}

X11SalFrame::X11SalFrame( SalFrame *pParent, SalFrameStyleFlags nSalFrameStyle,
                          SystemParentData const * pSystemParent ) :
    m_nXScreen( 0 ),
    maAlwaysOnTopRaiseTimer( "vcl::X11SalFrame maAlwaysOnTopRaiseTimer" )
{
    GenericUnixSalData *pData = GetGenericUnixSalData();

    mpParent                    = static_cast< X11SalFrame* >( pParent );

    mbTransientForRoot          = false;

    pDisplay_                   = vcl_sal::getSalDisplay(pData);
    // insert frame in framelist
    pDisplay_->registerFrame( this );

    mhWindow                    = None;
    mpSurface                   = nullptr;
    mhShellWindow               = None;
    mhStackingWindow            = None;
    mhForeignParent             = None;
    m_bSetFocusOnMap            = false;

    pGraphics_                  = nullptr;
    pFreeGraphics_              = nullptr;

    hCursor_                    = None;
    nCaptured_                  = 0;

    mbSendExtKeyModChange       = false;
    mnExtKeyMod                 = ModKeyFlags::NONE;

    nShowState_                 = X11ShowState::Unknown;
    nWidth_                     = 0;
    nHeight_                    = 0;
    nStyle_                     = SalFrameStyleFlags::NONE;
    mnExtStyle                  = 0;
    bAlwaysOnTop_               = false;

    // set bViewable_ to true: hack GetClientSize to report something
    // different to 0/0 before first map
    bViewable_                  = true;
    bMapped_                    = false;
    bDefaultPosition_           = true;
    nVisibility_                = VisibilityFullyObscured;
    m_nWorkArea                 = 0;
    m_bXEmbed                   = false;


    mpInputContext              = nullptr;
    mbInputFocus                = False;

    maAlwaysOnTopRaiseTimer.SetInvokeHandler( LINK( this, X11SalFrame, HandleAlwaysOnTopRaise ) );
    maAlwaysOnTopRaiseTimer.SetTimeout( 100 );

    meWindowType                = WMWindowType::Normal;
    mbMaximizedVert             = false;
    mbMaximizedHorz             = false;
    mbFullScreen                = false;
    m_bIsPartialFullScreen = false;

    mnIconID                    = SV_ICON_ID_OFFICE;

    if( mpParent )
        mpParent->maChildren.push_back( this );

    Init( nSalFrameStyle, GetDisplay()->GetDefaultXScreen(), pSystemParent );
}

X11SalFrame::~X11SalFrame()
{
    notifyDelete();

    m_vClipRectangles.clear();

    if( mhStackingWindow )
        aPresentationReparentList.remove( mhStackingWindow );

    // remove from parent's list
    if( mpParent )
        mpParent->maChildren.remove( this );

    // deregister on SalDisplay
    pDisplay_->deregisterFrame( this );

    // unselect all events, some may be still in the queue anyway
    if( ! IsSysChildWindow() )
        XSelectInput( GetXDisplay(), GetShellWindow(), 0 );
    XSelectInput( GetXDisplay(), GetWindow(), 0 );

    ShowFullScreen( false, 0 );

    if( bMapped_ )
        Show( false );

    if( mpInputContext )
    {
        mpInputContext->UnsetICFocus();
        mpInputContext->Unmap();
        mpInputContext.reset();
    }

    if( GetWindow() == hPresentationWindow )
    {
        hPresentationWindow = None;
        doReparentPresentationDialogues( GetDisplay() );
    }

    pGraphics_.reset();
    pFreeGraphics_.reset();

    // reset all OpenGL contexts using this window
    rtl::Reference<OpenGLContext> pContext = ImplGetSVData()->maGDIData.mpLastContext;
    while( pContext.is() )
    {
        if (static_cast<const GLX11Window&>(pContext->getOpenGLWindow()).win == mhWindow)
            pContext->reset();
        pContext = pContext->mpPrevContext;
    }

    if (mpSurface)
        cairo_surface_destroy(mpSurface);

    XDestroyWindow( GetXDisplay(), mhWindow );
}

void X11SalFrame::SetExtendedFrameStyle( SalExtStyle nStyle )
{
    if( nStyle != mnExtStyle && ! IsChildWindow() )
    {
        mnExtStyle = nStyle;
        updateWMClass();
    }
}

const SystemEnvData& X11SalFrame::GetSystemData() const
{
    X11SalFrame *pFrame = const_cast<X11SalFrame*>(this);
    pFrame->maSystemChildData.pDisplay      = GetXDisplay();
    pFrame->maSystemChildData.SetWindowHandle(pFrame->GetWindow());
    pFrame->maSystemChildData.pSalFrame     = pFrame;
    pFrame->maSystemChildData.pWidget       = nullptr;
    pFrame->maSystemChildData.pVisual       = GetDisplay()->GetVisual( m_nXScreen ).GetVisual();
    pFrame->maSystemChildData.nScreen       = m_nXScreen.getXScreen();
    pFrame->maSystemChildData.toolkit       = SystemEnvData::Toolkit::Gen;
    pFrame->maSystemChildData.platform      = SystemEnvData::Platform::Xcb;
    return maSystemChildData;
}

SalGraphics *X11SalFrame::AcquireGraphics()
{
    if( pGraphics_ )
        return nullptr;

    if( pFreeGraphics_ )
    {
        pGraphics_      = std::move(pFreeGraphics_);
    }
    else
    {
        pGraphics_.reset(new X11SalGraphics());
        pGraphics_->Init(*this, GetWindow(), m_nXScreen);
    }

    return pGraphics_.get();
}

void X11SalFrame::ReleaseGraphics( SalGraphics *pGraphics )
{
    SAL_WARN_IF( pGraphics != pGraphics_.get(), "vcl""SalFrame::ReleaseGraphics pGraphics!=pGraphics_" );

    if( pGraphics != pGraphics_.get() )
        return;

    pFreeGraphics_  = std::move(pGraphics_);
}

void X11SalFrame::updateGraphics( bool bClear )
{
    Drawable aDrawable = bClear ? None : GetWindow();
    if( pGraphics_ )
        pGraphics_->SetDrawable( aDrawable, mpSurface, m_nXScreen );
    if( pFreeGraphics_ )
        pFreeGraphics_->SetDrawable( aDrawable, mpSurface, m_nXScreen );
}

void X11SalFrame::SetIcon( sal_uInt16 nIcon )
{
    if (  IsChildWindow() )
        return;

    // 0 == default icon -> #1
    if ( nIcon == 0 )
        nIcon = 1;

    mnIconID = nIcon;

    NetWmIconData netwm_icon;
    CreateNetWmAppIcon( nIcon, netwm_icon );

    if( !netwm_icon.empty() && GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ))
        XChangeProperty( GetXDisplay(), mhWindow,
            GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::NET_WM_ICON ),
            XA_CARDINAL, 32, PropModeReplace, reinterpret_cast<unsigned char*>(netwm_icon.data()), netwm_icon.size());
}

void X11SalFrame::SetMaxClientSize( tools::Long nWidth, tools::Long nHeight )
{
    if(  IsChildWindow() )
        return;

    if( !GetShellWindow() ||
        (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
        return;

    XSizeHints* pHints = XAllocSizeHints();
    tools::Long nSupplied = 0;
    XGetWMNormalHints( GetXDisplay(),
                       GetShellWindow(),
                       pHints,
                       &nSupplied
                       );
    pHints->max_width   = nWidth;
    pHints->max_height  = nHeight;
    pHints->flags |= PMaxSize;
    XSetWMNormalHints( GetXDisplay(),
                       GetShellWindow(),
                       pHints );
    XFree( pHints );
}

void X11SalFrame::SetMinClientSize( tools::Long nWidth, tools::Long nHeight )
{
    if(  IsChildWindow() )
        return;

    if( !GetShellWindow() ||
        (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) == SalFrameStyleFlags::FLOAT )
        return;

    XSizeHints* pHints = XAllocSizeHints();
    tools::Long nSupplied = 0;
    XGetWMNormalHints( GetXDisplay(),
                       GetShellWindow(),
                       pHints,
                       &nSupplied
                       );
    pHints->min_width   = nWidth;
    pHints->min_height  = nHeight;
    pHints->flags |= PMinSize;
    XSetWMNormalHints( GetXDisplay(),
                       GetShellWindow(),
                       pHints );
    XFree( pHints );
}

// Show + Pos (x,y,z) + Size (width,height)

void X11SalFrame::Show( bool bVisible, bool bNoActivate )
{
    if( ( bVisible && bMapped_ )
        || ( !bVisible && !bMapped_ ) )
        return;

    // HACK: this is a workaround for (at least) kwin
    // even though transient frames should be kept above their parent
    // this does not necessarily hold true for DOCK type windows
    // so artificially set ABOVE and remove it again on hide
    if( mpParent && mpParent->m_bIsPartialFullScreen && pDisplay_->getWMAdaptor()->isLegacyPartialFullscreen())
        pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bVisible );

    bMapped_   = bVisible;
    bViewable_ = bVisible;
    setXEmbedInfo();
    if( bVisible )
    {
        if( ! (nStyle_ & SalFrameStyleFlags::INTRO) )
        {
            // hide all INTRO frames
            for (auto pSalFrame : GetDisplay()->getFrames() )
            {
                const X11SalFrame* pFrame = static_castconst X11SalFrame* >( pSalFrame );
                // look for intro bit map; if present, hide it
                if( pFrame->nStyle_ & SalFrameStyleFlags::INTRO )
                {
                    if( pFrame->bMapped_ )
                        const_cast<X11SalFrame*>(pFrame)->Show( false );
                }
            }
        }

        // update NET_WM_STATE which may have been deleted due to earlier Show(false)
        if( nShowState_ == X11ShowState::Hidden )
            GetDisplay()->getWMAdaptor()->frameIsMapping( this );

        /*
         *  Actually this is rather exotic and currently happens only in conjunction
         *  with the basic dialogue editor,
         *  which shows a frame and instantly hides it again. After that the
         *  editor window is shown and the WM takes this as an opportunity
         *  to show our hidden transient frame also. So Show( false ) must
         *  withdraw the frame AND delete the WM_TRANSIENT_FOR property.
         *  In case the frame is shown again, the transient hint must be restored here.
         */

        if(    ! IsChildWindow()
            && ! IsOverrideRedirect()
            && ! IsFloatGrabWindow()
            && mpParent
            )
        {
            GetDisplay()->getWMAdaptor()->changeReferenceFrame( this, mpParent );
        }

        // #i45160# switch to desktop where a dialog with parent will appear
        if( mpParent && mpParent->m_nWorkArea != m_nWorkArea )
            GetDisplay()->getWMAdaptor()->switchToWorkArea( mpParent->m_nWorkArea );

        if( IsFloatGrabWindow() &&
            mpParent &&
            nVisibleFloats == 0 &&
            ! GetDisplay()->GetCaptureFrame() )
        {
            /* #i39420#
             * outsmart KWin's "focus strictly under mouse" mode
             * which insists on taking the focus from the document
             * to the new float. Grab focus to parent frame BEFORE
             * showing the float (cannot grab it to the float
             * before show).
             */

            XGrabPointer( GetXDisplay(),
                          mpParent->GetWindow(),
                          True,
                          PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
                          GrabModeAsync,
                          GrabModeAsync,
                          None,
                          mpParent ? mpParent->GetCursor() : None,
                          CurrentTime
                          );
        }

        Time nUserTime = 0;
        if( ! bNoActivate && !(nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
            nUserTime = pDisplay_->GetX11ServerTime();
        GetDisplay()->getWMAdaptor()->setUserTime( this, nUserTime );
        if( ! bNoActivate && (nStyle_ & SalFrameStyleFlags::TOOLWINDOW) )
            m_bSetFocusOnMap = true;

        // actually map the window
        if( m_bXEmbed )
            askForXEmbedFocus( 0 );
        else
        {
            if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
            {
                if( IsChildWindow() )
                    XMapWindow( GetXDisplay(), GetShellWindow() );
                XSelectInput( GetXDisplay(), GetShellWindow(), CLIENT_EVENTS );
            }
            if( nStyle_ & SalFrameStyleFlags::FLOAT )
                XMapRaised( GetXDisplay(), GetWindow() );
            else
                XMapWindow( GetXDisplay(), GetWindow() );
        }
        XSelectInput( GetXDisplay(), GetWindow(), CLIENT_EVENTS );

        if( maGeometry.width() > 0
            && maGeometry.height() > 0
            && (   nWidth_  != static_cast<int>(maGeometry.width())
                || nHeight_ != static_cast<int>(maGeometry.height()) ) )
        {
            nWidth_  = maGeometry.width();
            nHeight_ = maGeometry.height();
        }

        XSync( GetXDisplay(), False );

        if( IsFloatGrabWindow() )
        {
            /*
             *  Sawfish and twm can be switched to enter-exit focus behaviour. In this case
             *  we must grab the pointer else the dumb WM will put the focus to the
             *  override-redirect float window. The application window will be deactivated
             *  which causes that the floats are destroyed, so the user can never click on
             *  a menu because it vanishes as soon as he enters it.
             */

            nVisibleFloats++;
            if( nVisibleFloats == 1 && ! GetDisplay()->GetCaptureFrame() )
            {
                /* #i39420# now move grab to the new float window */
                XGrabPointer( GetXDisplay(),
                              GetWindow(),
                              True,
                              PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
                              GrabModeAsync,
                              GrabModeAsync,
                              None,
                              mpParent ? mpParent->GetCursor() : None,
                              CurrentTime
                              );
            }
        }
        CallCallback( SalEvent::Resize, nullptr );

        /*
         *  sometimes a message box/dialogue is brought up when a frame is not mapped
         *  the corresponding TRANSIENT_FOR hint is then set to the root window
         *  so that the dialogue shows in all cases. Correct it here if the
         *  frame is shown afterwards.
         */

        if( ! IsChildWindow()
            && ! IsOverrideRedirect()
            && ! IsFloatGrabWindow()
            )
        {
            for (auto const& child : maChildren)
            {
                if( child->mbTransientForRoot )
                    GetDisplay()->getWMAdaptor()->changeReferenceFrame( child, this );
            }
        }
        /*
         *  leave X11ShowState::Unknown as this indicates first mapping
         *  and is only reset int HandleSizeEvent
         */

        if( nShowState_ != X11ShowState::Unknown )
            nShowState_ = X11ShowState::Normal;

        /*
         *  plugged windows don't necessarily get the
         *  focus on show because the parent may already be mapped
         *  and have the focus. So try to set the focus
         *  to the child on Show(true)
         */

        if( (nStyle_ & SalFrameStyleFlags::PLUG) && ! m_bXEmbed )
            XSetInputFocus( GetXDisplay(),
                            GetWindow(),
                            RevertToParent,
                            CurrentTime );

        if( mpParent )
        {
            // push this frame so it will be in front of its siblings
            // only necessary for insane transient behaviour of Dtwm/olwm
            mpParent->maChildren.remove( this );
            mpParent->maChildren.push_front(this);
        }
    }
    else
    {
        if( getInputContext() )
            getInputContext()->Unmap();

        if( ! IsChildWindow() )
        {
            /*  FIXME: Is deleting the property really necessary ? It hurts
             *  owner drawn windows at least.
             */

            if( mpParent && ! (nStyle_ & SalFrameStyleFlags::OWNERDRAWDECORATION) )
                XDeleteProperty( GetXDisplay(), GetShellWindow(), GetDisplay()->getWMAdaptor()->getAtom( WMAdaptor::WM_TRANSIENT_FOR ) );
            XWithdrawWindow( GetXDisplay(), GetShellWindow(), m_nXScreen.getXScreen() );
        }
        else if( ! m_bXEmbed )
            XUnmapWindow( GetXDisplay(), GetWindow() );

        nShowState_ = X11ShowState::Hidden;
        if( IsFloatGrabWindow() && nVisibleFloats )
        {
            nVisibleFloats--;
            if( nVisibleFloats == 0  && ! GetDisplay()->GetCaptureFrame() )
                XUngrabPointer( GetXDisplay(),
                                CurrentTime );
        }
        // flush here; there may be a very seldom race between
        // the display connection used for clipboard and our connection
        Flush();
    }
}

void X11SalFrame::ToTop( SalFrameToTop nFlags )
{
    if( ( nFlags & SalFrameToTop::RestoreWhenMin )
        && ! ( nStyle_ & SalFrameStyleFlags::FLOAT )
        && nShowState_ != X11ShowState::Hidden
        && nShowState_ != X11ShowState::Unknown
        )
    {
        GetDisplay()->getWMAdaptor()->frameIsMapping( this );
        if( GetWindow() != GetShellWindow() && ! IsSysChildWindow() )
            XMapWindow( GetXDisplay(), GetShellWindow() );
        XMapWindow( GetXDisplay(), GetWindow() );
    }

    ::Window aToTopWindow = IsSysChildWindow() ? GetWindow() : GetShellWindow();
    if( ! (nFlags & SalFrameToTop::GrabFocusOnly) )
    {
        XRaiseWindow( GetXDisplay(), aToTopWindow );
    }

    if( ( ( nFlags & SalFrameToTop::GrabFocus ) || ( nFlags & SalFrameToTop::GrabFocusOnly ) )
        && bMapped_ )
    {
        if( m_bXEmbed )
            askForXEmbedFocus( 0 );
        else
            XSetInputFocus( GetXDisplay(), aToTopWindow, RevertToParent, CurrentTime );
    }
    else if( ( nFlags & SalFrameToTop::RestoreWhenMin ) || ( nFlags & SalFrameToTop::ForegroundTask ) )
    {
            Time nTimestamp = pDisplay_->GetX11ServerTime();
            GetDisplay()->getWMAdaptor()->activateWindow( this, nTimestamp );
    }
}

void X11SalFrame::GetWorkArea( AbsoluteScreenPixelRectangle& rWorkArea )
{
    rWorkArea = pDisplay_->getWMAdaptor()->getWorkArea( 0 );
}

void X11SalFrame::GetClientSize( tools::Long &rWidth, tools::Long &rHeight )
{
    if( ! bViewable_  )
    {
        rWidth = rHeight = 0;
        return;
    }

    rWidth  = maGeometry.width();
    rHeight = maGeometry.height();

    if( !rWidth || !rHeight )
    {
        XWindowAttributes aAttrib;

        XGetWindowAttributes( GetXDisplay(), GetWindow(), &aAttrib );

        rWidth = aAttrib.width;
        rHeight = aAttrib.height;
        maGeometry.setSize({ aAttrib.width, aAttrib.height });
    }
}

void X11SalFrame::Center( )
{
    int             nX, nY;
    AbsoluteScreenPixelSize aRealScreenSize(GetDisplay()->getDataForScreen(m_nXScreen).m_aSize);
    AbsoluteScreenPixelRectangle aScreen({ 0, 0 }, aRealScreenSize);

    if( GetDisplay()->IsXinerama() )
    {
        // get xinerama screen we are on
        // if there is a parent, use its center for screen determination
        // else use the pointer
        ::Window aRoot, aChild;
        int root_x, root_y, x, y;
        unsigned int mask;
        if( mpParent )
        {
            root_x = mpParent->maGeometry.x() + mpParent->maGeometry.width() / 2;
            root_y = mpParent->maGeometry.y() + mpParent->maGeometry.height() / 2;
        }
        else
            XQueryPointer( GetXDisplay(),
                           GetShellWindow(),
                           &aRoot, &aChild,
                           &root_x, &root_y,
                           &x, &y,
                           &mask );
        const std::vector< AbsoluteScreenPixelRectangle >& rScreens = GetDisplay()->GetXineramaScreens();
        for(const auto & rScreen : rScreens)
            if( rScreen.Contains( AbsoluteScreenPixelPoint( root_x, root_y ) ) )
            {
                aScreen.SetPos(rScreen.GetPos());
                aRealScreenSize = rScreen.GetSize();
                break;
            }
    }

    if( mpParent )
    {
        X11SalFrame* pFrame = mpParent;
        while( pFrame->mpParent )
            pFrame = pFrame->mpParent;
        if( pFrame->maGeometry.width() < 1  || pFrame->maGeometry.height() < 1 )
        {
            AbsoluteScreenPixelRectangle aRect;
            pFrame->GetPosSize( aRect );
            pFrame->maGeometry.setPosSize(tools::Rectangle(aRect));
        }

        if( pFrame->nStyle_ & SalFrameStyleFlags::PLUG )
        {
            ::Window aRoot;
            unsigned int nScreenWidth, nScreenHeight, bw, depth;
            int nScreenX, nScreenY;
            XGetGeometry( GetXDisplay(),
                          pFrame->GetShellWindow(),
                          &aRoot,
                          &nScreenX, &nScreenY,
                          &nScreenWidth, &nScreenHeight,
                          &bw, &depth );
            aScreen = {{ nScreenX, nScreenY }, Size(nScreenWidth, nScreenHeight)};
        }
        else
            aScreen = AbsoluteScreenPixelRectangle(pFrame->maGeometry.posSize());
    }

    if( mpParent && mpParent->nShowState_ == X11ShowState::Normal )
    {
        if( maGeometry.width() >= mpParent->maGeometry.width() &&
            maGeometry.height() >= mpParent->maGeometry.height() )
        {
            nX = aScreen.getX() + 40;
            nY = aScreen.getY() + 40;
        }
        else
        {
            // center the window relative to the top level frame
            nX = (aScreen.GetWidth()  - static_cast<int>(maGeometry.width()) ) / 2 + aScreen.getX();
            nY = (aScreen.GetHeight() - static_cast<int>(maGeometry.height())) / 2 + aScreen.getY();
        }
    }
    else
    {
        // center the window relative to screen
        nX = (aRealScreenSize.getWidth()  - static_cast<int>(maGeometry.width()) ) / 2 + aScreen.getX();
        nY = (aRealScreenSize.getHeight() - static_cast<int>(maGeometry.height())) / 2 + aScreen.getY();
    }
    nX = nX < 0 ? 0 : nX;
    nY = nY < 0 ? 0 : nY;

    bDefaultPosition_ = False;
    if( mpParent )
    {
        nX -= mpParent->maGeometry.x();
        nY -= mpParent->maGeometry.y();
    }

    SetPosSize({ { nX, nY }, maGeometry.size() });
}

void X11SalFrame::updateScreenNumber()
{
    if( GetDisplay()->IsXinerama() && GetDisplay()->GetXineramaScreens().size() > 1 )
    {
        AbsoluteScreenPixelPoint aPoint( maGeometry.x(), maGeometry.y() );
        const std::vector<AbsoluteScreenPixelRectangle>& rScreenRects( GetDisplay()->GetXineramaScreens() );
        size_t nScreens = rScreenRects.size();
        for( size_t i = 0; i < nScreens; i++ )
        {
            if( rScreenRects[i].Contains( aPoint ) )
            {
                maGeometry.setScreen(static_cast<unsigned int>(i));
                break;
            }
        }
    }
    else
        maGeometry.setScreen(m_nXScreen.getXScreen());
}

void X11SalFrame::SetPosSize( tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight, sal_uInt16 nFlags )
{
    if( nStyle_ & SalFrameStyleFlags::PLUG )
        return;

    // relative positioning in X11SalFrame::SetPosSize
    AbsoluteScreenPixelRectangle aPosSize( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ), AbsoluteScreenPixelSize( maGeometry.width(), maGeometry.height() ) );
    aPosSize.Normalize();

    if( ! ( nFlags & SAL_FRAME_POSSIZE_X ) )
    {
        nX = aPosSize.Left();
        if( mpParent )
            nX -= mpParent->maGeometry.x();
    }
    if( ! ( nFlags & SAL_FRAME_POSSIZE_Y ) )
    {
        nY = aPosSize.Top();
        if( mpParent )
            nY -= mpParent->maGeometry.y();
    }
    if( ! ( nFlags & SAL_FRAME_POSSIZE_WIDTH ) )
        nWidth = aPosSize.GetWidth();
    if( ! ( nFlags & SAL_FRAME_POSSIZE_HEIGHT ) )
        nHeight = aPosSize.GetHeight();

    aPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( nX, nY ), AbsoluteScreenPixelSize( nWidth, nHeight ) );

    if( ! ( nFlags & ( SAL_FRAME_POSSIZE_X | SAL_FRAME_POSSIZE_Y ) ) )
    {
        if( bDefaultPosition_ )
        {
            maGeometry.setSize(Size(aPosSize.GetSize()));
            Center();
        }
        else
            SetSize( Size( nWidth, nHeight ) );
    }
    else
        SetPosSize( aPosSize );

    bDefaultPosition_ = False;
}

void X11SalFrame::SetAlwaysOnTop( bool bOnTop )
{
    if( ! IsOverrideRedirect() )
    {
        bAlwaysOnTop_ = bOnTop;
        pDisplay_->getWMAdaptor()->enableAlwaysOnTop( this, bOnTop );
    }
}

constexpr auto FRAMESTATE_MASK_MAXIMIZED_GEOMETRY =
     vcl::WindowDataMask::MaximizedX     | vcl::WindowDataMask::MaximizedY |
     vcl::WindowDataMask::MaximizedWidth | vcl::WindowDataMask::MaximizedHeight;

void X11SalFrame::SetWindowState( const vcl::WindowData *pState )
{
    if (pState == nullptr)
        return;

    // Request for position or size change
    if (pState->mask() & vcl::WindowDataMask::PosSize)
    {
        /* #i44325#
         * if maximized, set restore size and guess maximized size from last time
         * in state change below maximize window
         */

        if( ! IsChildWindow() &&
            (pState->mask() & vcl::WindowDataMask::PosSizeState) == vcl::WindowDataMask::PosSizeState &&
            (pState->state() & vcl::WindowState::Maximized) &&
            (pState->mask() & FRAMESTATE_MASK_MAXIMIZED_GEOMETRY) == FRAMESTATE_MASK_MAXIMIZED_GEOMETRY
            )
        {
            XSizeHints* pHints = XAllocSizeHints();
            tools::Long nSupplied = 0;
            XGetWMNormalHints( GetXDisplay(),
                               GetShellWindow(),
                               pHints,
                               &nSupplied );
            pHints->flags |= PPosition | PWinGravity;
            pHints->x = pState->x();
            pHints->y = pState->y();
            pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
            XSetWMNormalHints(GetXDisplay(), GetShellWindow(), pHints);
            XFree( pHints );

            XMoveResizeWindow(GetXDisplay(), GetShellWindow(), pState->x(), pState->y(),
                              pState->width(), pState->height());
            // guess maximized geometry from last time
            maGeometry.setPos({ pState->GetMaximizedX(), pState->GetMaximizedY() });
            maGeometry.setSize({ static_cast<tools::Long>(pState->GetMaximizedWidth()), static_cast<tools::Long>(pState->GetMaximizedHeight()) });
            cairo_xlib_surface_set_size(mpSurface,  pState->GetMaximizedWidth(), pState->GetMaximizedHeight());
            updateScreenNumber();
        }
        else
        {
            bool bDoAdjust = false;
            AbsoluteScreenPixelRectangle aPosSize;
            // initialize with current geometry
            if ((pState->mask() & vcl::WindowDataMask::PosSize) != vcl::WindowDataMask::PosSize)
                GetPosSize(aPosSize);

            sal_uInt16 nPosFlags = 0;

            // change requested properties
            if (pState->mask() & vcl::WindowDataMask::X)
            {
                aPosSize.SetPosX(pState->x() - (mpParent ? mpParent->maGeometry.x() : 0));
                nPosFlags |= SAL_FRAME_POSSIZE_X;
            }
            if (pState->mask() & vcl::WindowDataMask::Y)
            {
                aPosSize.SetPosY(pState->y() - (mpParent ? mpParent->maGeometry.y() : 0));
                nPosFlags |= SAL_FRAME_POSSIZE_Y;
            }
            if (pState->mask() & vcl::WindowDataMask::Width)
            {
                tools::Long nWidth = pState->width() > 0 ? pState->width()  - 1 : 0;
                aPosSize.setWidth (nWidth);
                bDoAdjust = true;
            }
            if (pState->mask() & vcl::WindowDataMask::Height)
            {
                int nHeight = pState->height() > 0 ? pState->height() - 1 : 0;
                aPosSize.setHeight (nHeight);
                bDoAdjust = true;
            }

            const AbsoluteScreenPixelSize& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;

            if( bDoAdjust && aPosSize.GetWidth() <= aScreenSize.Width()
                && aPosSize.GetHeight() <= aScreenSize.Height() )
            {
                SalFrameGeometry aGeom = maGeometry;

                if( ! (nStyle_ & ( SalFrameStyleFlags::FLOAT | SalFrameStyleFlags::PLUG ) ) &&
                    mpParent && aGeom.leftDecoration() == 0 && aGeom.topDecoration() == 0)
                {
                    aGeom = mpParent->maGeometry;
                    if (aGeom.leftDecoration() == 0 && aGeom.topDecoration() == 0)
                        aGeom.setDecorations(5, 20, 5, 5);
                }

                auto nRight = aPosSize.Right() + (mpParent ? mpParent->maGeometry.x() : 0);
                auto nBottom = aPosSize.Bottom() + (mpParent ? mpParent->maGeometry.y() : 0);
                auto nLeft = aPosSize.Left() + (mpParent ? mpParent->maGeometry.x() : 0);
                auto nTop = aPosSize.Top() + (mpParent ? mpParent->maGeometry.y() : 0);

                // adjust position so that frame fits onto screen
                if( nRight+static_cast<tools::Long>(aGeom.rightDecoration()) > aScreenSize.Width()-1 )
                    aPosSize.Move( aScreenSize.Width() - nRight - static_cast<tools::Long>(aGeom.rightDecoration()), 0 );
                if( nBottom+static_cast<tools::Long>(aGeom.bottomDecoration()) > aScreenSize.Height()-1 )
                    aPosSize.Move( 0, aScreenSize.Height() - nBottom - static_cast<tools::Long>(aGeom.bottomDecoration()) );
                if( nLeft < static_cast<tools::Long>(aGeom.leftDecoration()) )
                    aPosSize.Move( static_cast<tools::Long>(aGeom.leftDecoration()) - nLeft, 0 );
                if( nTop < static_cast<tools::Long>(aGeom.topDecoration()) )
                    aPosSize.Move( 0, static_cast<tools::Long>(aGeom.topDecoration()) - nTop );
            }

            SetPosSize(aPosSize.getX(), aPosSize.getY(),
                       aPosSize.GetWidth(), aPosSize.GetHeight(),
                       SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT |
                       nPosFlags);
        }
    }

    // request for status change
    if (!(pState->mask() & vcl::WindowDataMask::State))
        return;

    if (pState->state() & vcl::WindowState::Maximized)
    {
        nShowState_ = X11ShowState::Normal;
        if( ! (pState->state() & (vcl::WindowState::MaximizedHorz|vcl::WindowState::MaximizedVert) ) )
            Maximize();
        else
        {
            bool bHorz(pState->state() & vcl::WindowState::MaximizedHorz);
            bool bVert(pState->state() & vcl::WindowState::MaximizedVert);
            GetDisplay()->getWMAdaptor()->maximizeFrame( this, bHorz, bVert );
        }
        maRestorePosSize = AbsoluteScreenPixelRectangle(pState->posSize());
    }
    else if( mbMaximizedHorz || mbMaximizedVert )
        GetDisplay()->getWMAdaptor()->maximizeFrame( thisfalsefalse );

    if (pState->state() & vcl::WindowState::Minimized)
    {
        if (nShowState_ == X11ShowState::Unknown)
            nShowState_ = X11ShowState::Normal;
        Minimize();
    }
    if (pState->state() & vcl::WindowState::Normal)
    {
        if (nShowState_ != X11ShowState::Normal)
            Restore();
    }
}

bool X11SalFrame::GetWindowState( vcl::WindowData* pState )
{
    if( X11ShowState::Minimized == nShowState_ )
        pState->setState(vcl::WindowState::Minimized);
    else
        pState->setState(vcl::WindowState::Normal);

    AbsoluteScreenPixelRectangle aPosSize;
    if( maRestorePosSize.IsEmpty() )
        GetPosSize( aPosSize );
    else
        aPosSize = maRestorePosSize;

    if( mbMaximizedHorz )
        pState->rState() |= vcl::WindowState::MaximizedHorz;
    if( mbMaximizedVert )
        pState->rState() |= vcl::WindowState::MaximizedVert;

    pState->setPosSize(tools::Rectangle(aPosSize));
    pState->setMask(vcl::WindowDataMask::PosSizeState);

    if (! maRestorePosSize.IsEmpty() )
    {
        GetPosSize( aPosSize );
        pState->rState() |= vcl::WindowState::Maximized;
        pState->SetMaximizedX(aPosSize.Left());
        pState->SetMaximizedY(aPosSize.Top());
        pState->SetMaximizedWidth(aPosSize.GetWidth());
        pState->SetMaximizedHeight(aPosSize.GetHeight());
        pState->rMask() |= FRAMESTATE_MASK_MAXIMIZED_GEOMETRY;
    }

    return true;
}

void X11SalFrame::SetMenu( SalMenu* )
{
}

void X11SalFrame::GetPosSize( AbsoluteScreenPixelRectangle &rPosSize )
{
    if( maGeometry.width() < 1 || maGeometry.height() < 1 )
    {
        const AbsoluteScreenPixelSize& aScreenSize = pDisplay_->getDataForScreen( m_nXScreen ).m_aSize;
        tools::Long w = aScreenSize.Width()  - maGeometry.leftDecoration() - maGeometry.rightDecoration();
        tools::Long h = aScreenSize.Height() - maGeometry.topDecoration() - maGeometry.bottomDecoration();

        rPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ), AbsoluteScreenPixelSize( w, h ) );
    }
    else
        rPosSize = AbsoluteScreenPixelRectangle( AbsoluteScreenPixelPoint( maGeometry.x(), maGeometry.y() ),
                              AbsoluteScreenPixelSize( maGeometry.width(), maGeometry.height() ) );
}

void X11SalFrame::SetSize( const Size &rSize )
{
    if( rSize.IsEmpty() )
        return;

    if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
        && ! IsChildWindow()
        && ( nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT )
    {
        XSizeHints* pHints = XAllocSizeHints();
        tools::Long nSupplied = 0;
        XGetWMNormalHints( GetXDisplay(),
                           GetShellWindow(),
                           pHints,
                           &nSupplied
                           );
        pHints->min_width   = rSize.Width();
        pHints->min_height  = rSize.Height();
        pHints->max_width   = rSize.Width();
        pHints->max_height  = rSize.Height();
        pHints->flags |= PMinSize | PMaxSize;
        XSetWMNormalHints( GetXDisplay(),
                           GetShellWindow(),
                           pHints );
        XFree( pHints );
    }
    XResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), rSize.Width(), rSize.Height() );
    if( GetWindow() != GetShellWindow() )
    {
        if( nStyle_ & SalFrameStyleFlags::PLUG )
            XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, rSize.Width(), rSize.Height() );
        else
            XResizeWindow( GetXDisplay(), GetWindow(), rSize.Width(), rSize.Height() );
    }

    cairo_xlib_surface_set_size(mpSurface, rSize.Width(), rSize.Height());
    maGeometry.setSize(rSize);

    // allow the external status window to reposition
    if (mbInputFocus && mpInputContext != nullptr)
        mpInputContext->SetICFocus ( this );
}

void X11SalFrame::SetPosSize( const AbsoluteScreenPixelRectangle &rPosSize )
{
    XWindowChanges values;
    values.x        = rPosSize.Left();
    values.y        = rPosSize.Top();
    values.width    = rPosSize.GetWidth();
    values.height   = rPosSize.GetHeight();

    if( !values.width || !values.height )
        return;

    if( mpParent && ! IsSysChildWindow() )
    {
        if( AllSettings::GetLayoutRTL() )
            values.x = mpParent->maGeometry.width()-values.width-1-values.x;

        ::Window aChild;
        // coordinates are relative to parent, so translate to root coordinates
        XTranslateCoordinates( GetDisplay()->GetDisplay(),
                                mpParent->GetWindow(),
                                GetDisplay()->GetRootWindow( m_nXScreen ),
                                values.x, values.y,
                                &values.x, &values.y,
                                & aChild );
    }

    bool bMoved = false;
    bool bSized = false;
    if( values.x != maGeometry.x() || values.y != maGeometry.y() )
        bMoved = true;
    if( values.width != static_cast<int>(maGeometry.width()) || values.height != static_cast<int>(maGeometry.height()) )
        bSized = true;

    // do not set WMNormalHints for...
    if(
        // child windows
        ! IsChildWindow()
        // popups (menu, help window, etc.)
        &&  (nStyle_ & (SalFrameStyleFlags::FLOAT|SalFrameStyleFlags::OWNERDRAWDECORATION) ) != SalFrameStyleFlags::FLOAT
        // shown, sizeable windows
        && ( nShowState_ == X11ShowState::Unknown ||
             nShowState_ == X11ShowState::Hidden ||
             ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE )
             )
        )
    {
        XSizeHints* pHints = XAllocSizeHints();
        tools::Long nSupplied = 0;
        XGetWMNormalHints( GetXDisplay(),
                           GetShellWindow(),
                           pHints,
                           &nSupplied
                           );
        if( ! ( nStyle_ & SalFrameStyleFlags::SIZEABLE ) )
        {
            pHints->min_width   = rPosSize.GetWidth();
            pHints->min_height  = rPosSize.GetHeight();
            pHints->max_width   = rPosSize.GetWidth();
            pHints->max_height  = rPosSize.GetHeight();
            pHints->flags |= PMinSize | PMaxSize;
        }
        if( nShowState_ == X11ShowState::Unknown || nShowState_ == X11ShowState::Hidden )
        {
            pHints->flags |= PPosition | PWinGravity;
            pHints->x           = values.x;
            pHints->y           = values.y;
            pHints->win_gravity = pDisplay_->getWMAdaptor()->getPositionWinGravity();
        }
        if( mbFullScreen )
        {
            pHints->max_width   = 10000;
            pHints->max_height  = 10000;
            pHints->flags |= PMaxSize;
        }
        XSetWMNormalHints( GetXDisplay(),
                           GetShellWindow(),
                           pHints );
        XFree( pHints );
    }

    XMoveResizeWindow( GetXDisplay(), IsSysChildWindow() ? GetWindow() : GetShellWindow(), values.x, values.y, values.width, values.height );
    if( GetShellWindow() != GetWindow() )
    {
        if( nStyle_ & SalFrameStyleFlags::PLUG )
            XMoveResizeWindow( GetXDisplay(), GetWindow(), 0, 0, values.width, values.height );
        else
            XMoveResizeWindow( GetXDisplay(), GetWindow(), values.x, values.y, values.width, values.height );
    }

    cairo_xlib_surface_set_size(mpSurface, values.width, values.height);
    maGeometry.setPosSize({ values.x, values.y }, { values.width, values.height });
    if( IsSysChildWindow() && mpParent )
        // translate back to root coordinates
        maGeometry.move(mpParent->maGeometry.x(), mpParent->maGeometry.y());

    updateScreenNumber();
    if( bSized && ! bMoved )
        CallCallback( SalEvent::Resize, nullptr );
    else if( bMoved && ! bSized )
        CallCallback( SalEvent::Move, nullptr );
    else
        CallCallback( SalEvent::MoveResize, nullptr );

    // allow the external status window to reposition
    if (mbInputFocus && mpInputContext != nullptr)
        mpInputContext->SetICFocus ( this );
}

void X11SalFrame::Minimize()
{
    if( IsSysChildWindow() )
        return;

    if( X11ShowState::Unknown == nShowState_ || X11ShowState::Hidden == nShowState_ )
    {
        SAL_WARN( "vcl""X11SalFrame::Minimize on withdrawn window" );
        return;
    }

    if( XIconifyWindow( GetXDisplay(),
                        GetShellWindow(),
                        pDisplay_->GetDefaultXScreen().getXScreen() ) )
        nShowState_ = X11ShowState::Minimized;
}

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.35 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.