/* -*- 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 .
 */
 
#pragma once
 
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <epoxy/glx.h>
 
#include <rtl/string.hxx>
#include <unx/saltype.h>
#include <vcl/opengl/OpenGLContext.hxx>
#include <vcl/ptrstyle.hxx>
#include <sal/types.h>
#include <cassert>
#include <list>
#include <vector>
#include <tools/gen.hxx>
#include <salwtype.hxx>
#include <unx/gendata.hxx>
#include <unx/gendisp.hxx>
#include <o3tl/enumarray.hxx>
 
#include <vclpluginapi.h>
 
class   SalDisplay;
class   SalColormap;
class   SalVisual;
class   SalXLib;
 
 
/* From <X11/Intrinsic.h> */
typedef unsigned long Pixel;
 
class   BitmapPalette;
class   SalFrame;
class   ColorMask;
 
namespace vcl_sal { class WMAdaptor; }
 
// server vendor
 
typedef enum  {
    vendor_none = 0,
    vendor_sun,
    vendor_unknown
} srv_vendor_t;
 
extern "C" srv_vendor_t sal_GetServerVendor( Display *p_display );
 
// MSB/Bigendian view (Color == RGB, r=0xFF0000, g=0xFF00, b=0xFF)
 
class SalVisual : public XVisualInfo
{
public:
                            SalVisual();
                            SalVisual( const XVisualInfo* pXVI );
 
    VisualID        GetVisualId() const { return visualid; }
    Visual         *GetVisual() const { return visual; }
    int             GetClass() const { return c_class; }
    int             GetDepth() const { return depth; }
};
 
// A move-only flag, used by SalColormap to track ownership of its m_aVisual.visual:
struct OwnershipFlag {
    bool owner = false;
 
    OwnershipFlag() = default;
 
    OwnershipFlag(OwnershipFlag && other) noexcept: owner(other.owner) { other.owner = false; }
 
    OwnershipFlag & operator =(OwnershipFlag && other) noexcept {
        assert(&other != this);
        owner = other.owner;
        other.owner = false;
        return *this;
    }
};
 
class SalColormap
{
    const SalDisplay*       m_pDisplay;
    Colormap                m_hColormap;
    std::vector<Color>      m_aPalette;         // Pseudocolor
    SalVisual               m_aVisual;
    OwnershipFlag           m_aVisualOwnership;
    Pixel                   m_nWhitePixel;
    Pixel                   m_nBlackPixel;
    Pixel                   m_nUsed;            // Pseudocolor
 
public:
    SalColormap( const SalDisplay*  pSalDisplay,
                 Colormap           hColormap,
                 SalX11Screen       nXScreen );
    SalColormap( sal_uInt16         nDepth );
    SalColormap();
 
    ~SalColormap();
 
    SalColormap(SalColormap &&) = default;
    SalColormap & operator =(SalColormap &&) = default;
 
    Colormap            GetXColormap() const { return m_hColormap; }
    const SalDisplay*   GetDisplay() const { return m_pDisplay; }
    inline  Display*            GetXDisplay() const;
    const SalVisual&    GetVisual() const { return m_aVisual; }
    Pixel               GetWhitePixel() const { return m_nWhitePixel; }
    Pixel               GetBlackPixel() const { return m_nBlackPixel; }
 
    bool            GetXPixels( XColor  &rColor,
                                    int      r,
                                    int      g,
                                    int      b ) const;
    inline  bool            GetXPixel( XColor  &rColor,
                                           int      r,
                                           int      g,
                                           int      b ) const;
};
 
class SalI18N_InputMethod;
 
typedef int(*YieldFunc)(int fd, void* data);
 
class SalXLib
{
    timeval         m_aTimeout;
    sal_uLong       m_nTimeoutMS;
    int             m_pTimeoutFDS[2];
 
    int             nFDs_;
    fd_set          aReadFDS_;
    fd_set          aExceptionFDS_;
 
    Display             *m_pDisplay;
    std::unique_ptr<SalI18N_InputMethod> m_pInputMethod;
 
public:
    SalXLib();
    ~SalXLib();
    void    Init();
 
    bool    Yield( bool bWait, bool bHandleAllCurrentEvents );
    void    Wakeup();
    void            TriggerUserEventProcessing();
 
    void    Insert( int fd, void* data,
                            YieldFunc   pending,
                            YieldFunc   queued,
                            YieldFunc   handle );
    void    Remove( int fd );
 
    void    StartTimer( sal_uInt64 nMS );
    void    StopTimer();
 
    bool    CheckTimeout( bool bExecuteTimers = true );
 
    SalI18N_InputMethod* GetInputMethod() const { return m_pInputMethod.get(); }
    Display*             GetDisplay() const { return m_pDisplay; }
};
 
class SalI18N_KeyboardExtension;
class AttributeProvider;
 
extern "C" {
    typedef Bool(*X_if_predicate)(Display*,XEvent*,XPointer);
}
 
class GLX11Window final : public GLWindow
{
public:
    Display*           dpy;
    int                screen;
    Window             win;
    XVisualInfo*       vi;
    GLXContext         ctx;
    OString            GLXExtensions;
 
    bool HasGLXExtension(const char* name) const;
 
    GLX11Window();
    virtual bool Synchronize(bool bOnoff) const override;
    virtual ~GLX11Window() override;
};
 
class VCLPLUG_GEN_PUBLIC SalDisplay : public SalGenericDisplay
{
public:
 
    struct ScreenData
    {
        bool                m_bInit;
 
        ::Window            m_aRoot;
        ::Window            m_aRefWindow;
        AbsoluteScreenPixelSize m_aSize;
        SalVisual           m_aVisual;
        SalColormap         m_aColormap;
        GC                  m_aMonoGC;
        GC                  m_aCopyGC;
        GC                  m_aAndInvertedGC;
        GC                  m_aAndGC;
        GC                  m_aOrGC;
        GC                  m_aStippleGC;
        Pixmap              m_hInvert50;
 
        ScreenData() :
        m_bInit( false ),
        m_aRoot( None ),
        m_aRefWindow( None ),
        m_aMonoGC( None ),
        m_aCopyGC( None ),
        m_aAndInvertedGC( None ),
        m_aAndGC( None ),
        m_aOrGC( None ),
        m_aStippleGC( None ),
        m_hInvert50( None )
        {}
    };
 
protected:
    SalXLib        *pXLib_;
    SalI18N_KeyboardExtension   *mpKbdExtension;
 
    Display        *pDisp_;             // X Display
 
    SalX11Screen                 m_nXDefaultScreen;
    std::vector< ScreenData >    m_aScreens;
    ScreenData      m_aInvalidScreenData;
    Pair            aResolution_;       // [dpi]
    sal_uLong       nMaxRequestSize_;   // [byte]
 
    srv_vendor_t    meServerVendor;
 
    // until x bytes
 
    o3tl::enumarray<PointerStyle, Cursor> aPointerCache_;
 
    // Keyboard
    bool            bNumLockFromXS_;    // Num Lock handled by X Server
    int             nNumLockIndex_;     // modifier index in modmap
    KeySym          nShiftKeySym_;      // first shift modifier
    KeySym          nCtrlKeySym_;       // first control modifier
    KeySym          nMod1KeySym_;       // first mod1 modifier
 
    std::unique_ptr<vcl_sal::WMAdaptor> m_pWMAdaptor;
 
    bool            m_bXinerama;
    std::vector< AbsoluteScreenPixelRectangle > m_aXineramaScreens;
    std::vector< int > m_aXineramaScreenIndexMap;
    std::list<SalObject*> m_aSalObjects;
 
    mutable Time    m_nLastUserEventTime; // mutable because changed on first access
 
    virtual void    Dispatch( XEvent *pEvent ) = 0;
    SAL_DLLPRIVATE void InitXinerama();
    SAL_DLLPRIVATE void InitRandR( ::Window aRoot ) const;
    SAL_DLLPRIVATE static void DeInitRandR();
    SAL_DLLPRIVATE void processRandREvent( XEvent* );
 
    SAL_DLLPRIVATE void doDestruct();
    SAL_DLLPRIVATE void addXineramaScreenUnique( int i, tools::Long i_nX, tools::Long i_nY, tools::Long i_nWidth, tools::Long i_nHeight );
    SAL_DLLPRIVATE Time GetEventTimeImpl( bool bAlwaysReget = false ) const;
public:
    SAL_DLLPRIVATE static bool BestVisual(Display *pDisp, int nScreen, XVisualInfo &rVI);
 
    SAL_DLLPRIVATE SalDisplay( Display* pDisp );
 
    virtual        ~SalDisplay() override;
 
    SAL_DLLPRIVATE void Init();
 
#ifdef DBG_UTIL
    void            PrintInfo() const;
    void            DbgPrintDisplayEvent(const char *pComment, const XEvent *pEvent) const;
#endif
 
    SAL_DLLPRIVATE void Beep() const;
 
    SAL_DLLPRIVATE void ModifierMapping();
    SAL_DLLPRIVATE void SimulateKeyPress( sal_uInt16 nKeyCode );
    SAL_DLLPRIVATE KeyIndicatorState  GetIndicatorState() const;
    SAL_DLLPRIVATE OUString GetKeyNameFromKeySym( KeySym keysym ) const;
    SAL_DLLPRIVATE OUString GetKeyName( sal_uInt16 nKeyCode ) const;
    SAL_DLLPRIVATE sal_uInt16 GetKeyCode( KeySym keysym, char*pcPrintable ) const;
    SAL_DLLPRIVATE KeySym GetKeySym( XKeyEvent      *pEvent,
                               char           *pPrintable,
                               int            *pLen,
                               KeySym         *pUnmodifiedKeySym,
                               Status         *pStatus,
                               XIC = nullptr ) const;
 
    SAL_DLLPRIVATE Cursor GetPointer( PointerStyle ePointerStyle );
    SAL_DLLPRIVATE int CaptureMouse( SalFrame *pCapture );
 
    SAL_DLLPRIVATE ScreenData* initScreen( SalX11Screen nXScreen ) const;
    const ScreenData&     getDataForScreen( SalX11Screen nXScreen ) const
    {
        if( nXScreen.getXScreen() >= m_aScreens.size() )
            return m_aInvalidScreenData;
        if( ! m_aScreens[nXScreen.getXScreen()].m_bInit )
            initScreen( nXScreen );
        return m_aScreens[nXScreen.getXScreen()];
    }
 
    ::Window         GetDrawable( SalX11Screen nXScreen ) const { return getDataForScreen( nXScreen ).m_aRefWindow; }
    Display        *GetDisplay() const { return pDisp_; }
    const SalX11Screen& GetDefaultXScreen() const { return m_nXDefaultScreen; }
    const AbsoluteScreenPixelSize& GetScreenSize( SalX11Screen nXScreen ) const { return getDataForScreen( nXScreen ).m_aSize; }
    srv_vendor_t    GetServerVendor() const { return meServerVendor; }
    bool            IsDisplay() const { return !!pXLib_; }
    const SalColormap&    GetColormap( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aColormap; }
    const SalVisual&      GetVisual( SalX11Screen nXScreen ) const { return getDataForScreen(nXScreen).m_aVisual; }
    const Pair     &GetResolution() const { return aResolution_; }
    Time            GetLastUserEventTime() const { return GetEventTimeImpl(); }
    // this is an equivalent of gdk_x11_get_server_time()
    Time            GetX11ServerTime() const { return GetEventTimeImpl( true ); }
 
    SalI18N_InputMethod*        GetInputMethod()  const { return pXLib_->GetInputMethod();  }
    SalI18N_KeyboardExtension*  GetKbdExtension() const { return mpKbdExtension; }
    void            SetKbdExtension(SalI18N_KeyboardExtension *pKbdExtension)
    { mpKbdExtension = pKbdExtension; }
    ::vcl_sal::WMAdaptor* getWMAdaptor() const { return m_pWMAdaptor.get(); }
    bool            IsXinerama() const { return m_bXinerama; }
    const std::vector< AbsoluteScreenPixelRectangle >& GetXineramaScreens() const { return m_aXineramaScreens; }
    ::Window        GetRootWindow( SalX11Screen nXScreen ) const
            { return getDataForScreen( nXScreen ).m_aRoot; }
    unsigned int GetXScreenCount() const { return m_aScreens.size(); }
 
    const SalFrameSet& getFrames() const { return m_aFrames; }
 
    std::list< SalObject* >& getSalObjects() { return m_aSalObjects; }
};
 
inline  Display *SalColormap::GetXDisplay() const
{ return m_pDisplay->GetDisplay(); }
 
class SalX11Display final : public SalDisplay
{
public:
             SalX11Display( Display* pDisp );
    virtual ~SalX11Display() override;
 
    virtual void        Dispatch( XEvent *pEvent ) override;
    virtual void        Yield();
    virtual void        TriggerUserEventProcessing() override;
 
    bool                IsEvent();
    void                SetupInput();
};
 
namespace vcl_sal {
    // get foreign key names
    OUString getKeysymReplacementName(
        std::u16string_view pLang,
        KeySym nSymbol );
 
    inline SalDisplay *getSalDisplay(GenericUnixSalData const * data)
    {
        assert(data != nullptr);
        return static_cast<SalDisplay *>(data->GetDisplay());
    }
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V1052 Declaring virtual methods in a class marked as 'final' is pointless. Consider inspecting the 'Yield' method of the 'SalX11Display' class.