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

Quelle  salnativewidgets-gtk.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/.
 */


#include <sal/config.h>
#include <sal/log.hxx>
#include <osl/module.h>

#include <config_cairo_canvas.h>

#include <unx/gtk/gtkframe.hxx>
#include <unx/gtk/gtkdata.hxx>
#include <unx/gtk/gtkinst.hxx>
#include <unx/gtk/gtkgdi.hxx>
#include <unx/gtk/gtkbackend.hxx>
#include <vcl/BitmapTools.hxx>
#include <vcl/CairoFormats.hxx>
#include <vcl/decoview.hxx>
#include <vcl/settings.hxx>
#include <unx/fontmanager.hxx>
#include <o3tl/string_view.hxx>
#include <scrollbarvalue.hxx>

#include <IconThemeSelector.hxx>
#include "custom-theme.hxx"
#include <vcl/themecolors.hxx>
#include "gtkcairo.hxx"

GtkCssProvider*  GtkSalGraphics::mpCustomThemeProvider = nullptr;
GtkStyleContext* GtkSalGraphics::mpWindowStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpLinkButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpEntryStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpTextViewStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpVScrollbarStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpVScrollbarContentsStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpVScrollbarTroughStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpVScrollbarSliderStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpVScrollbarButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpHScrollbarStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpHScrollbarContentsStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpHScrollbarTroughStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpHScrollbarSliderStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpHScrollbarButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpToolbarStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpToolButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpToolbarSeparatorStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpCheckButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpCheckButtonCheckStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpRadioButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpRadioButtonRadioStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpSpinStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpSpinUpStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpSpinDownStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxBoxStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxEntryStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxButtonBoxStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpComboboxButtonArrowStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpListboxStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpListboxBoxStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpListboxButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpListboxButtonBoxStyle= nullptr;
GtkStyleContext* GtkSalGraphics::mpListboxButtonArrowStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpFrameInStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpFrameOutStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpFixedHoriLineStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpFixedVertLineStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpTreeHeaderButtonStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpProgressBarStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpProgressBarTroughStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpProgressBarProgressStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookStackStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderTabsStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderTabsTabStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderTabsTabLabelStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderTabsTabActiveLabelStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpNotebookHeaderTabsTabHoverLabelStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuBarStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuBarItemStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuWindowStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuItemStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuItemArrowStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpMenuItemLabelStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpCheckMenuItemStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpCheckMenuItemCheckStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpRadioMenuItemStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpRadioMenuItemRadioStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpSeparatorMenuItemStyle = nullptr;
GtkStyleContext* GtkSalGraphics::mpSeparatorMenuItemSeparatorStyle = nullptr;
gint GtkSalGraphics::mnVerticalSeparatorMinWidth = 0;

#if !GTK_CHECK_VERSION(4, 0, 0)
static void style_context_get_margin(GtkStyleContext *pContext, GtkBorder *pMargin)
{
#if GTK_CHECK_VERSION(4, 0, 0)
    gtk_style_context_get_margin(pContext, pMargin);
#else
    gtk_style_context_get_margin(pContext, gtk_style_context_get_state(pContext), pMargin);
#endif
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
static void style_context_get_border(GtkStyleContext* pContext, GtkBorder* pBorder)
{
#if GTK_CHECK_VERSION(4, 0, 0)
    gtk_style_context_get_border(pContext, pBorder);
#else
    gtk_style_context_get_border(pContext, gtk_style_context_get_state(pContext), pBorder);
#endif
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
static void style_context_get_padding(GtkStyleContext* pContext, GtkBorder* pPadding)
{
#if GTK_CHECK_VERSION(4, 0, 0)
    gtk_style_context_get_padding(pContext, pPadding);
#else
    gtk_style_context_get_padding(pContext, gtk_style_context_get_state(pContext), pPadding);
#endif
}
#endif

bool GtkSalGraphics::style_loaded = false;
/************************************************************************
 * State conversion
 ************************************************************************/

#if !GTK_CHECK_VERSION(4, 0, 0)
static GtkStateFlags NWConvertVCLStateToGTKState(ControlState nVCLState)
{
    GtkStateFlags nGTKState = GTK_STATE_FLAG_NORMAL;

    if (!( nVCLState & ControlState::ENABLED ))
    {
        nGTKState = GTK_STATE_FLAG_INSENSITIVE;
    }

    if ( nVCLState & ControlState::PRESSED )
    {
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_ACTIVE);
    }

    if ( nVCLState & ControlState::ROLLOVER )
    {
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_PRELIGHT);
    }

    if ( nVCLState & ControlState::SELECTED )
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_SELECTED);

    if ( nVCLState & ControlState::FOCUSED )
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_FOCUSED);

    if (AllSettings::GetLayoutRTL())
    {
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_DIR_RTL);
    }
    else
    {
        nGTKState = static_cast<GtkStateFlags>(nGTKState | GTK_STATE_FLAG_DIR_LTR);
    }

    return nGTKState;
}

namespace {

enum class RenderType {
    BackgroundAndFrame = 1,
    Check,
    Background,
    MenuSeparator,
    ToolbarSeparator,
    Separator,
    Arrow,
    Radio,
    Scrollbar,
    Spinbutton,
    Combobox,
    Expander,
    Icon,
    Progress,
    TabItem,
    Focus
};

}

static void NWCalcArrowRect( const tools::Rectangle& rButton, tools::Rectangle& ;rArrow )
{
    // Size the arrow appropriately
    Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
    rArrow.SetSize( aSize );

    rArrow.SetPos( Point(
        rButton.Left() + ( rButton.GetWidth()  - rArrow.GetWidth()  ) / 2,
        rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
        ) );
}

tools::Rectangle GtkSalGraphics::NWGetSpinButtonRect( ControlPart nPart, tools::Rectangle aAreaRect)
{
    gint w, h;
    gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h);
    gint icon_size = std::max(w, h);

    GtkBorder padding, border;
    style_context_get_padding(mpSpinUpStyle, &padding);
    style_context_get_border(mpSpinUpStyle, &border);

    gint buttonWidth = icon_size + padding.left + padding.right +
        border.left + border.right;

    tools::Rectangle buttonRect(Point(0, aAreaRect.Top()), Size(buttonWidth, 0));
    buttonRect.setHeight(aAreaRect.GetHeight());
    tools::Rectangle partRect(buttonRect);
    if ( nPart == ControlPart::ButtonUp )
    {
        if (AllSettings::GetLayoutRTL())
            partRect.SetPosX(aAreaRect.Left());
        else
            partRect.SetPosX(aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()));
    }
    else if( nPart == ControlPart::ButtonDown )
    {
        if (AllSettings::GetLayoutRTL())
            partRect.SetPosX(aAreaRect.Left() + buttonRect.GetWidth());
        else
            partRect.SetPosX(aAreaRect.Left() + (aAreaRect.GetWidth() - 2 * buttonRect.GetWidth()));
    }
    else
    {
        if (AllSettings::GetLayoutRTL())
        {
            partRect.SetRight( aAreaRect.Left() + aAreaRect.GetWidth() );
            partRect.SetLeft( aAreaRect.Left() + (2 * buttonRect.GetWidth()) - 1 );
        }
        else
        {
            partRect.SetRight( (aAreaRect.Left() + (aAreaRect.GetWidth() - 2 * buttonRect.GetWidth())) - 1 );
            partRect.SetLeft( aAreaRect.Left() );
        }
        partRect.SetTop( aAreaRect.Top() );
        partRect.SetBottom( aAreaRect.Bottom() );
    }

    return partRect;
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
namespace
{
    void QuerySize(GtkStyleContext *pContext, Size &rSize)
    {
        GtkBorder margin, border, padding;

        style_context_get_margin(pContext, &margin);
        style_context_get_border(pContext, &border);
        style_context_get_padding(pContext, &padding);

        int nMinWidth(0), nMinHeight(0);
        GtkStateFlags stateflags = gtk_style_context_get_state (pContext);
        gtk_style_context_get(pContext, stateflags,
                "min-width", &nMinWidth, "min-height", &nMinHeight, nullptr);
        nMinWidth += margin.left + margin.right + border.left + border.right + padding.left + padding.right;
        nMinHeight += margin.top + margin.bottom + border.top + border.bottom + padding.top + padding.bottom;

        rSize = Size(std::max<tools::Long>(rSize.Width(), nMinWidth), std::max<tools::Long>(rSize.Height(), nMinHeight));
    }
}
#endif

#if !GTK_CHECK_VERSION(4, 0, 0)
tools::Rectangle GtkSalGraphics::NWGetScrollButtonRect( ControlPart nPart, tools::Rectangle aAreaRect )
{
    tools::Rectangle  buttonRect;

    gboolean has_forward;
    gboolean has_forward2;
    gboolean has_backward;
    gboolean has_backward2;

    GtkStyleContext* pScrollbarStyle = nullptr;
    if ((nPart == ControlPart::ButtonLeft) || (nPart == ControlPart::ButtonRight))
        pScrollbarStyle = mpHScrollbarStyle;
    else // (nPart == ControlPart::ButtonUp) || (nPart == ControlPart::ButtonDown)
        pScrollbarStyle = mpVScrollbarStyle;

    gtk_style_context_get_style( pScrollbarStyle,
                                 "has-forward-stepper", &has_forward,
                                 "has-secondary-forward-stepper", &has_forward2,
                                 "has-backward-stepper", &has_backward,
                                 "has-secondary-backward-stepper", &has_backward2, nullptr );

    gint nFirst = 0;
    gint nSecond = 0;

    if ( has_forward )   nSecond += 1;
    if ( has_forward2 )  nFirst  += 1;
    if ( has_backward )  nFirst  += 1;
    if ( has_backward2 ) nSecond += 1;

    Size aSize;
    if (nPart == ControlPart::ButtonLeft || nPart == ControlPart::ButtonRight)
    {
        QuerySize(mpHScrollbarStyle, aSize);
        QuerySize(mpHScrollbarContentsStyle, aSize);
        QuerySize(mpHScrollbarButtonStyle, aSize);
    }
    else
    {
        QuerySize(mpVScrollbarStyle, aSize);
        QuerySize(mpVScrollbarContentsStyle, aSize);
        QuerySize(mpVScrollbarButtonStyle, aSize);
    }

    if (nPart == ControlPart::ButtonUp)
    {
        aSize.setHeight( aSize.Height() * nFirst );
        buttonRect.SetLeft(aAreaRect.Left());
        buttonRect.SetTop(aAreaRect.Top());
    }
    else if (nPart == ControlPart::ButtonLeft)
    {
        aSize.setWidth( aSize.Width() * nFirst );
        buttonRect.SetLeft(aAreaRect.Left());
        buttonRect.SetTop(aAreaRect.Top());
    }
    else if (nPart == ControlPart::ButtonDown)
    {
        aSize.setHeight( aSize.Height() * nSecond );
        buttonRect.SetLeft(aAreaRect.Left());
        buttonRect.SetTop(aAreaRect.Top() + aAreaRect.GetHeight() - aSize.Height());
    }
    else if (nPart == ControlPart::ButtonRight)
    {
        aSize.setWidth( aSize.Width() * nSecond );
        buttonRect.SetLeft(aAreaRect.Left() + aAreaRect.GetWidth() - aSize.Width());
        buttonRect.SetTop(aAreaRect.Top());
    }

    buttonRect.SetSize(aSize);

    return buttonRect;
}
#endif

static GtkWidget* gCacheWindow;
static GtkWidget* gDumbContainer;
#if GTK_CHECK_VERSION(4, 0, 0)
static GtkWidget* gVScrollbar;
static GtkWidget* gTextView;
#else
static GtkWidget* gComboBox;
static GtkWidget* gListBox;
static GtkWidget* gSpinBox;
static GtkWidget* gTreeViewWidget;
#endif
static GtkWidget* gHScrollbar;
static GtkWidget* gEntryBox;

namespace
{
    void style_context_set_state(GtkStyleContext* context, GtkStateFlags flags)
    {
#if !GTK_CHECK_VERSION(4, 0, 0)
        do
        {
            gtk_style_context_set_state(context, flags);
        }
        while ((context = gtk_style_context_get_parent(context)));
#else
        gtk_style_context_set_state(context, flags);
#endif
    }

    class StyleContextSave
    {
    private:
        std::vector<std::pair<GtkStyleContext*, GtkStateFlags>> m_aStates;
    public:
        void save(GtkStyleContext* context)
        {
#if !GTK_CHECK_VERSION(4, 0, 0)
            do
            {
                m_aStates.emplace_back(context, gtk_style_context_get_state(context));
            }
            while ((context = gtk_style_context_get_parent(context)));
#else
            m_aStates.emplace_back(context, gtk_style_context_get_state(context));
#endif
        }
        void restore()
        {
            for (auto a = m_aStates.rbegin(); a != m_aStates.rend(); ++a)
            {
                gtk_style_context_set_state(a->first, a->second);
            }
            m_aStates.clear();
        }
    };

#if !GTK_CHECK_VERSION(4, 0, 0)
    tools::Rectangle render_common(GtkStyleContext *pContext, cairo_t *cr, const tools::Rectangle &rIn, GtkStateFlags flags)
    {
        if (!pContext)
            return rIn;

        gtk_style_context_set_state(pContext, flags);

        tools::Rectangle aRect(rIn);
        GtkBorder margin;
        style_context_get_margin(pContext, &margin);

        aRect.AdjustLeft(margin.left );
        aRect.AdjustTop(margin.top );
        aRect.AdjustRight( -(margin.right) );
        aRect.AdjustBottom( -(margin.bottom) );

        gtk_render_background(pContext, cr, aRect.Left(), aRect.Top(),
                                            aRect.GetWidth(), aRect.GetHeight());
        gtk_render_frame(pContext, cr, aRect.Left(), aRect.Top(),
                                       aRect.GetWidth(), aRect.GetHeight());

        GtkBorder border, padding;
        style_context_get_border(pContext, &border);
        style_context_get_padding(pContext, &padding);

        aRect.AdjustLeft(border.left + padding.left );
        aRect.AdjustTop(border.top + padding.top );
        aRect.AdjustRight( -(border.right + padding.right) );
        aRect.AdjustBottom( -(border.bottom + padding.bottom) );

        return aRect;
    }
#endif
}

#if !GTK_CHECK_VERSION(4, 0, 0)
void GtkSalGraphics::PaintScrollbar(GtkStyleContext *context,
                                    cairo_t *cr,
                                    const tools::Rectangle& rControlRectangle,
                                    ControlPart nPart,
                                    const ImplControlValue& rValue )
{
    assert(rValue.getType() == ControlType::Scrollbar);
    const ScrollbarValue& rScrollbarVal = static_cast<const ScrollbarValue&>(rValue);
    tools::Rectangle        scrollbarRect;
    GtkStateFlags    stateFlags;
    GtkOrientation    scrollbarOrientation;
    tools::Rectangle        thumbRect = rScrollbarVal.maThumbRect;
    tools::Rectangle        button11BoundRect = rScrollbarVal.maButton1Rect;   // backward
    tools::Rectangle        button22BoundRect = rScrollbarVal.maButton2Rect;   // forward
    tools::Rectangle        button12BoundRect = rScrollbarVal.maButton1Rect;   // secondary forward
    tools::Rectangle        button21BoundRect = rScrollbarVal.maButton2Rect;   // secondary backward
    gdouble          arrow1Angle;                                        // backward
    gdouble          arrow2Angle;                                        // forward
    tools::Rectangle        arrowRect;
    gint            slider_width = 0;
    gint            stepper_size = 0;

    // make controlvalue rectangles relative to area
    thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
    button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
    button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
    button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
    button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );

    // Find the overall bounding rect of the control
    scrollbarRect = rControlRectangle;
    if (scrollbarRect.IsEmpty())
        return;

    gint slider_side;
    Size aSize;
    if (nPart == ControlPart::DrawBackgroundHorz)
    {
        QuerySize(mpHScrollbarStyle, aSize);
        QuerySize(mpHScrollbarContentsStyle, aSize);
        QuerySize(mpHScrollbarTroughStyle, aSize);
        QuerySize(mpHScrollbarSliderStyle, aSize);
        slider_side = aSize.Height();
        gtk_style_context_get(mpHScrollbarButtonStyle,
                              gtk_style_context_get_state(mpHScrollbarButtonStyle),
                              "min-height", &slider_width,
                              "min-width", &stepper_size, nullptr);
    }
    else
    {
        QuerySize(mpVScrollbarStyle, aSize);
        QuerySize(mpVScrollbarContentsStyle, aSize);
        QuerySize(mpVScrollbarTroughStyle, aSize);
        QuerySize(mpVScrollbarSliderStyle, aSize);
        slider_side = aSize.Width();
        gtk_style_context_get(mpVScrollbarButtonStyle,
                              gtk_style_context_get_state(mpVScrollbarButtonStyle),
                              "min-width", &slider_width,
                              "min-height", &stepper_size, nullptr);
    }

    gboolean has_forward;
    gboolean has_forward2;
    gboolean has_backward;
    gboolean has_backward2;

    gtk_style_context_get_style( context,
                                 "has-forward-stepper", &has_forward,
                                 "has-secondary-forward-stepper", &has_forward2,
                                 "has-backward-stepper", &has_backward,
                                 "has-secondary-backward-stepper", &has_backward2, nullptr );

    if ( nPart == ControlPart::DrawBackgroundHorz )
    {
        // Center vertically in the track
        scrollbarRect.Move( 0, (scrollbarRect.GetHeight() - slider_side) / 2 );
        scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), slider_side ) );
        thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_side) / 2 );
        thumbRect.SetSize( Size( thumbRect.GetWidth(), slider_side ) );

        scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
        arrow1Angle = G_PI * 3 / 2;
        arrow2Angle = G_PI / 2;

        if ( has_backward )
        {
            button12BoundRect.Move( stepper_size,
                                    (scrollbarRect.GetHeight() - slider_width) / 2 );
        }

        button11BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
        button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
        button12BoundRect.SetSize( Size( stepper_size, slider_width ) );

        if ( has_backward2 )
        {
            button22BoundRect.Move( stepper_size, (scrollbarRect.GetHeight() - slider_width) / 2 );
            button21BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
        }
        else
        {
            button22BoundRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
        }

        button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
        button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
    }
    else
    {
        // Center horizontally in the track
        scrollbarRect.Move( (scrollbarRect.GetWidth() - slider_side) / 2, 0 );
        scrollbarRect.SetSize( Size( slider_side, scrollbarRect.GetHeight() ) );
        thumbRect.Move( (scrollbarRect.GetWidth() - slider_side) / 2, 0 );
        thumbRect.SetSize( Size( slider_side, thumbRect.GetHeight() ) );

        scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
        arrow1Angle = 0;
        arrow2Angle = G_PI;

        if ( has_backward )
        {
            button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
                                    stepper_size );
        }
        button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
        button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
        button12BoundRect.SetSize( Size( slider_width, stepper_size ) );

        if ( has_backward2 )
        {
            button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size );
            button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
        }
        else
        {
            button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
        }

        button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
        button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
    }

    bool has_slider = !thumbRect.IsEmpty();

    // ----------------- CONTENTS
    GtkStyleContext* pScrollbarContentsStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                              mpVScrollbarContentsStyle : mpHScrollbarContentsStyle;

    gtk_render_background(gtk_widget_get_style_context(gCacheWindow), cr, 0, 0,
                          scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );

    gtk_render_background(context, cr, 0, 0,
                          scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
    gtk_render_frame(context, cr, 0, 0,
                     scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );

    gtk_render_background(pScrollbarContentsStyle, cr, 0, 0,
                          scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
    gtk_render_frame(pScrollbarContentsStyle, cr, 0, 0,
                     scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );

    bool backwardButtonInsensitive =
        rScrollbarVal.mnCur == rScrollbarVal.mnMin;
    bool forwardButtonInsensitive = rScrollbarVal.mnMax == 0 ||
        rScrollbarVal.mnCur + rScrollbarVal.mnVisibleSize >= rScrollbarVal.mnMax;

    // ----------------- BUTTON 1
    if ( has_backward )
    {
        stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton1State);
        if ( backwardButtonInsensitive )
            stateFlags = GTK_STATE_FLAG_INSENSITIVE;

        GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                                 mpVScrollbarButtonStyle : mpHScrollbarButtonStyle;

        gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags);

        gtk_render_background(pScrollbarButtonStyle, cr,
                              button11BoundRect.Left(), button11BoundRect.Top(),
                              button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
        gtk_render_frame(pScrollbarButtonStyle, cr,
                         button11BoundRect.Left(), button11BoundRect.Top(),
                         button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );

        // ----------------- ARROW 1
        NWCalcArrowRect( button11BoundRect, arrowRect );
        gtk_render_arrow(pScrollbarButtonStyle, cr,
                         arrow1Angle,
                         arrowRect.Left(), arrowRect.Top(),
                         MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) );
    }
    if ( has_forward2 )
    {
        stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton2State);
        if ( forwardButtonInsensitive )
            stateFlags = GTK_STATE_FLAG_INSENSITIVE;

        GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                                 mpVScrollbarButtonStyle : mpHScrollbarButtonStyle;

        gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags);

        gtk_render_background(pScrollbarButtonStyle, cr,
                              button12BoundRect.Left(), button12BoundRect.Top(),
                              button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
        gtk_render_frame(pScrollbarButtonStyle, cr,
                         button12BoundRect.Left(), button12BoundRect.Top(),
                         button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );

        // ----------------- ARROW 1
        NWCalcArrowRect( button12BoundRect, arrowRect );
        gtk_render_arrow(pScrollbarButtonStyle, cr,
                         arrow2Angle,
                         arrowRect.Left(), arrowRect.Top(),
                         MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) );
    }
    // ----------------- BUTTON 2

    if ( has_forward )
    {
        stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton2State);
        if ( forwardButtonInsensitive )
            stateFlags = GTK_STATE_FLAG_INSENSITIVE;

        GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                                 mpVScrollbarButtonStyle : mpHScrollbarButtonStyle;

        gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags);

        gtk_render_background(pScrollbarButtonStyle, cr,
                       button22BoundRect.Left(), button22BoundRect.Top(),
                       button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
        gtk_render_frame(pScrollbarButtonStyle, cr,
                       button22BoundRect.Left(), button22BoundRect.Top(),
                       button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );

        // ----------------- ARROW 2
        NWCalcArrowRect( button22BoundRect, arrowRect );
        gtk_render_arrow(pScrollbarButtonStyle, cr,
                         arrow2Angle,
                         arrowRect.Left(), arrowRect.Top(),
                         MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) );
    }

    if ( has_backward2 )
    {
        stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnButton1State);
        if ( backwardButtonInsensitive )
            stateFlags = GTK_STATE_FLAG_INSENSITIVE;

        GtkStyleContext* pScrollbarButtonStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                                 mpVScrollbarButtonStyle : mpHScrollbarButtonStyle;

        gtk_style_context_set_state(pScrollbarButtonStyle, stateFlags);

        gtk_render_background(pScrollbarButtonStyle, cr,
                              button21BoundRect.Left(), button21BoundRect.Top(),
                              button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
        gtk_render_frame(pScrollbarButtonStyle, cr,
                         button21BoundRect.Left(), button21BoundRect.Top(),
                         button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );

        // ----------------- ARROW 2
        NWCalcArrowRect( button21BoundRect, arrowRect );
        gtk_render_arrow(pScrollbarButtonStyle, cr,
                         arrow1Angle,
                         arrowRect.Left(), arrowRect.Top(),
                         MIN(arrowRect.GetWidth(), arrowRect.GetHeight()) );
    }

    // ----------------- TROUGH
    // trackrect matches that of ScrollBar::ImplCalc
    tools::Rectangle aTrackRect(Point(0, 0), scrollbarRect.GetSize());
    if (nPart == ControlPart::DrawBackgroundHorz)
    {
        tools::Rectangle aBtn1Rect = NWGetScrollButtonRect(ControlPart::ButtonLeft, aTrackRect);
        tools::Rectangle aBtn2Rect = NWGetScrollButtonRect(ControlPart::ButtonRight, aTrackRect);
        if (!aBtn1Rect.IsWidthEmpty())
            aTrackRect.SetLeft( aBtn1Rect.Right() );
        if (!aBtn2Rect.IsWidthEmpty())
            aTrackRect.SetRight( aBtn2Rect.Left() );
    }
    else
    {
        tools::Rectangle aBtn1Rect = NWGetScrollButtonRect(ControlPart::ButtonUp, aTrackRect);
        tools::Rectangle aBtn2Rect = NWGetScrollButtonRect(ControlPart::ButtonDown, aTrackRect);
        if (!aBtn1Rect.IsHeightEmpty())
            aTrackRect.SetTop( aBtn1Rect.Bottom() + 1 );
        if (!aBtn2Rect.IsHeightEmpty())
            aTrackRect.SetBottom( aBtn2Rect.Top() );
    }

    GtkStyleContext* pScrollbarTroughStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                              mpVScrollbarTroughStyle : mpHScrollbarTroughStyle;
    gtk_render_background(pScrollbarTroughStyle, cr, aTrackRect.Left(), aTrackRect.Top(),
                          aTrackRect.GetWidth(), aTrackRect.GetHeight() );
    gtk_render_frame(pScrollbarTroughStyle, cr, aTrackRect.Left(), aTrackRect.Top(),
                     aTrackRect.GetWidth(), aTrackRect.GetHeight() );

    // ----------------- THUMB
    if ( !has_slider )
        return;

    stateFlags = NWConvertVCLStateToGTKState(rScrollbarVal.mnThumbState);
    if ( rScrollbarVal.mnThumbState & ControlState::PRESSED )
        stateFlags = static_cast<GtkStateFlags>(stateFlags | GTK_STATE_FLAG_PRELIGHT);

    GtkStyleContext* pScrollbarSliderStyle = scrollbarOrientation == GTK_ORIENTATION_VERTICAL ?
                                              mpVScrollbarSliderStyle : mpHScrollbarSliderStyle;

    gtk_style_context_set_state(pScrollbarSliderStyle, stateFlags);

    GtkBorder margin;
    style_context_get_margin(pScrollbarSliderStyle, &margin);

    gtk_render_background(pScrollbarSliderStyle, cr,
                      thumbRect.Left() + margin.left, thumbRect.Top() + margin.top,
                      thumbRect.GetWidth() - margin.left - margin.right,
                      thumbRect.GetHeight() - margin.top - margin.bottom);

    gtk_render_frame(pScrollbarSliderStyle, cr,
                      thumbRect.Left() + margin.left, thumbRect.Top() + margin.top,
                      thumbRect.GetWidth() - margin.left - margin.right,
                      thumbRect.GetHeight() - margin.top - margin.bottom);
}

void GtkSalGraphics::PaintOneSpinButton( GtkStyleContext *context,
                                         cairo_t *cr,
                                         ControlPart nPart,
                                         tools::Rectangle aAreaRect,
                                         ControlState nState )
{
    GtkBorder            padding, border;

    GtkStateFlags stateFlags = NWConvertVCLStateToGTKState(nState);
    tools::Rectangle buttonRect = NWGetSpinButtonRect( nPart, aAreaRect );

    gtk_style_context_set_state(context, stateFlags);

    style_context_get_padding(context, &padding);
    style_context_get_border(context, &border);

    gtk_render_background(context, cr,
                          buttonRect.Left(), buttonRect.Top(),
                          buttonRect.GetWidth(), buttonRect.GetHeight() );

    gint iconWidth = buttonRect.GetWidth() - padding.left - padding.right - border.left - border.right;
    gint iconHeight = buttonRect.GetHeight() - padding.top - padding.bottom - border.top - border.bottom;

    const char* icon = (nPart == ControlPart::ButtonUp) ? "list-add-symbolic" : "list-remove-symbolic";
    GtkIconTheme *pIconTheme = gtk_icon_theme_get_for_screen(gtk_widget_get_screen(mpWindow));

    gint scale = gtk_style_context_get_scale (context);
    GtkIconInfo *info = gtk_icon_theme_lookup_icon_for_scale(pIconTheme, icon, std::min(iconWidth, iconHeight), scale,
                                                   static_cast<GtkIconLookupFlags>(0));

    GdkPixbuf *pixbuf = gtk_icon_info_load_symbolic_for_context(info, context, nullptr, nullptr);
    g_object_unref(info);

    iconWidth = gdk_pixbuf_get_width(pixbuf)/scale;
    iconHeight = gdk_pixbuf_get_height(pixbuf)/scale;
    tools::Rectangle arrowRect(buttonRect.Center() - Point(iconWidth / 2, iconHeight / 2),
                               Size(iconWidth, iconHeight));

    gtk_style_context_save (context);
    gtk_style_context_set_scale (context, 1);
    gtk_render_icon(context, cr, pixbuf, arrowRect.Left(), arrowRect.Top());
    gtk_style_context_restore (context);
    g_object_unref(pixbuf);

    gtk_render_frame(context, cr,
                     buttonRect.Left(), buttonRect.Top(),
                     buttonRect.GetWidth(), buttonRect.GetHeight() );
}

void GtkSalGraphics::PaintSpinButton(GtkStateFlags flags,
                                     cairo_t *cr,
                                     const tools::Rectangle& rControlRectangle,
                                     ControlPart nPart,
                                     const ImplControlValue& rValue )
{
    const SpinbuttonValue *pSpinVal = (rValue.getType() == ControlType::SpinButtons) ? static_cast<const SpinbuttonValue *>(&rValue) : nullptr;
    ControlPart upBtnPart = ControlPart::ButtonUp;
    ControlState upBtnState = ControlState::NONE;
    ControlPart downBtnPart = ControlPart::ButtonDown;
    ControlState downBtnState = ControlState::NONE;

    if ( pSpinVal )
    {
        upBtnPart = pSpinVal->mnUpperPart;
        upBtnState = pSpinVal->mnUpperState;

        downBtnPart = pSpinVal->mnLowerPart;
        downBtnState = pSpinVal->mnLowerState;
    }

    if (nPart == ControlPart::Entire)
    {
        gtk_style_context_set_state(mpWindowStyle, flags);

        gtk_render_background(mpWindowStyle, cr,
                              0, 0,
                              rControlRectangle.GetWidth(), rControlRectangle.GetHeight());

        gtk_style_context_set_state(mpSpinStyle, flags);

        gtk_render_background(mpSpinStyle, cr,
                              0, 0,
                              rControlRectangle.GetWidth(), rControlRectangle.GetHeight());
    }

    cairo_translate(cr, -rControlRectangle.Left(), -rControlRectangle.Top());
    PaintOneSpinButton(mpSpinUpStyle, cr, upBtnPart, rControlRectangle, upBtnState );
    PaintOneSpinButton(mpSpinDownStyle, cr, downBtnPart, rControlRectangle, downBtnState );
    cairo_translate(cr, rControlRectangle.Left(), rControlRectangle.Top());

    if (nPart == ControlPart::Entire)
    {
        gtk_render_frame(mpSpinStyle, cr,
                         0, 0,
                         rControlRectangle.GetWidth(), rControlRectangle.GetHeight() );
    }
}

#define FALLBACK_ARROW_SIZE gint(11 * 0.85)

tools::Rectangle GtkSalGraphics::NWGetComboBoxButtonRect(ControlType nType,
                                                   ControlPart nPart,
                                                   tools::Rectangle aAreaRect )
{
    tools::Rectangle    aButtonRect;

    GtkBorder padding;
    if (nType == ControlType::Listbox)
        style_context_get_padding(mpListboxButtonStyle, &padding);
    else
        style_context_get_padding(mpButtonStyle, &padding);

    gint nArrowWidth = FALLBACK_ARROW_SIZE;
    gtk_style_context_get(mpComboboxButtonArrowStyle,
        gtk_style_context_get_state(mpComboboxButtonArrowStyle),
        "min-width", &nArrowWidth, nullptr);

    gint nButtonWidth = nArrowWidth + padding.left + padding.right;
    if( nPart == ControlPart::ButtonDown )
    {
        Point aPos(aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth, aAreaRect.Top());
        if (AllSettings::GetLayoutRTL())
            aPos.setX( aAreaRect.Left() );
        aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
        aButtonRect.SetPos(aPos);
    }
    else if( nPart == ControlPart::SubEdit )
    {
        gint adjust_left = padding.left;
        gint adjust_top = padding.top;
        gint adjust_right = padding.right;
        gint adjust_bottom = padding.bottom;

        aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - (adjust_left + adjust_right),
                                   aAreaRect.GetHeight() - (adjust_top + adjust_bottom)) );
        Point aEditPos = aAreaRect.TopLeft();
        if (AllSettings::GetLayoutRTL())
            aEditPos.AdjustX(nButtonWidth );
        else
            aEditPos.AdjustX(adjust_left );
        aEditPos.AdjustY(adjust_top );
        aButtonRect.SetPos( aEditPos );
    }

    return aButtonRect;
}

void GtkSalGraphics::PaintCombobox( GtkStateFlags flags, cairo_t *cr,
                                    const tools::Rectangle& rControlRectangle,
                                    ControlType nType,
                                    ControlPart nPart )
{
    tools::Rectangle        areaRect;
    tools::Rectangle        buttonRect;
    tools::Rectangle        arrowRect;

    // Find the overall bounding rect of the buttons's drawing area,
    // plus its actual draw rect excluding adornment
    areaRect = rControlRectangle;

    buttonRect = NWGetComboBoxButtonRect(ControlType::Combobox, ControlPart::ButtonDown, areaRect);

    tools::Rectangle        aEditBoxRect( areaRect );
    aEditBoxRect.SetSize( Size( areaRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
    if (AllSettings::GetLayoutRTL())
        aEditBoxRect.SetPos( Point( areaRect.Left() + buttonRect.GetWidth(), areaRect.Top() ) );

    gint arrow_width = FALLBACK_ARROW_SIZE, arrow_height = FALLBACK_ARROW_SIZE;
    if (nType == ControlType::Combobox)
    {
        gtk_style_context_get(mpComboboxButtonArrowStyle,
            gtk_style_context_get_state(mpComboboxButtonArrowStyle),
            "min-width", &arrow_width, "min-height", &arrow_height, nullptr);
    }
    else if (nType == ControlType::Listbox)
    {
        gtk_style_context_get(mpListboxButtonArrowStyle,
            gtk_style_context_get_state(mpListboxButtonArrowStyle),
            "min-width", &arrow_width, "min-height", &arrow_height, nullptr);
    }

    arrowRect.SetSize(Size(arrow_width, arrow_height));
    arrowRect.SetPos( Point( buttonRect.Left() + static_cast<gint>((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
                             buttonRect.Top() + static_cast<gint>((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );


    tools::Rectangle aRect(Point(0, 0), Size(areaRect.GetWidth(), areaRect.GetHeight()));

    if (nType == ControlType::Combobox)
    {
        if( nPart == ControlPart::Entire )
        {
            render_common(mpComboboxStyle, cr, aRect, flags);
            render_common(mpComboboxBoxStyle, cr, aRect, flags);
            tools::Rectangle aEntryRect(Point(aEditBoxRect.Left() - areaRect.Left(),
                                 aEditBoxRect.Top() - areaRect.Top()),
                                 Size(aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight()));

            GtkJunctionSides eJuncSides = gtk_style_context_get_junction_sides(mpComboboxEntryStyle);
            if (AllSettings::GetLayoutRTL())
                gtk_style_context_set_junction_sides(mpComboboxEntryStyle, GTK_JUNCTION_LEFT);
            else
                gtk_style_context_set_junction_sides(mpComboboxEntryStyle, GTK_JUNCTION_RIGHT);
            render_common(mpComboboxEntryStyle, cr, aEntryRect, flags);
            gtk_style_context_set_junction_sides(mpComboboxEntryStyle, eJuncSides);
        }

        tools::Rectangle aButtonRect(Point(buttonRect.Left() - areaRect.Left(), buttonRect.Top() - areaRect.Top()),
                              Size(buttonRect.GetWidth(), buttonRect.GetHeight()));
        GtkJunctionSides eJuncSides = gtk_style_context_get_junction_sides(mpComboboxButtonStyle);
        if (AllSettings::GetLayoutRTL())
            gtk_style_context_set_junction_sides(mpComboboxButtonStyle, GTK_JUNCTION_RIGHT);
        else
            gtk_style_context_set_junction_sides(mpComboboxButtonStyle, GTK_JUNCTION_LEFT);
        render_common(mpComboboxButtonStyle, cr, aButtonRect, flags);
        gtk_style_context_set_junction_sides(mpComboboxButtonStyle, eJuncSides);

        gtk_render_arrow(mpComboboxButtonArrowStyle, cr,
                         G_PI,
                         (arrowRect.Left() - areaRect.Left()), (arrowRect.Top() - areaRect.Top()),
                         arrowRect.GetWidth() );
    }
    else if (nType == ControlType::Listbox)
    {
        if( nPart == ControlPart::ListboxWindow )
        {
            /* render the popup window with the menu style */
            gtk_render_frame(mpMenuStyle, cr,
                             0, 0,
                             areaRect.GetWidth(), areaRect.GetHeight());
        }
        else
        {
            render_common(mpListboxStyle, cr, aRect, flags);
            render_common(mpListboxButtonStyle, cr, aRect, flags);
            render_common(mpListboxBoxStyle, cr, aRect, flags);

            gtk_render_arrow(mpListboxButtonArrowStyle, cr,
                             G_PI,
                             (arrowRect.Left() - areaRect.Left()), (arrowRect.Top() - areaRect.Top()),
                             arrowRect.GetWidth() );
        }
    }
}

static void appendComboEntry(GtkWidgetPath* pSiblingsPath)
{
    gtk_widget_path_append_type(pSiblingsPath, GTK_TYPE_ENTRY);
    gtk_widget_path_iter_set_object_name(pSiblingsPath, -1, "entry");
    gtk_widget_path_iter_add_class(pSiblingsPath, -1, "combo");
}

static void appendComboButton(GtkWidgetPath* pSiblingsPath)
{
    gtk_widget_path_append_type(pSiblingsPath, GTK_TYPE_BUTTON);
    gtk_widget_path_iter_set_object_name(pSiblingsPath, -1, "button");
    gtk_widget_path_iter_add_class(pSiblingsPath, -1, "combo");
}

static GtkWidgetPath* buildLTRComboSiblingsPath()
{
    GtkWidgetPath* pSiblingsPath = gtk_widget_path_new();

    appendComboEntry(pSiblingsPath);
    appendComboButton(pSiblingsPath);

    return pSiblingsPath;
}

static GtkWidgetPath* buildRTLComboSiblingsPath()
{
    GtkWidgetPath* pSiblingsPath = gtk_widget_path_new();

    appendComboButton(pSiblingsPath);
    appendComboEntry(pSiblingsPath);

    return pSiblingsPath;
}


GtkStyleContext* GtkSalGraphics::makeContext(GtkWidgetPath *pPath, GtkStyleContext *pParent)
{
    GtkStyleContext* context = gtk_style_context_new();
    gtk_style_context_set_screen(context, gtk_widget_get_screen(mpWindow));
    gtk_style_context_set_path(context, pPath);
    if (pParent == nullptr)
    {
        GtkWidget* pTopLevel = widget_get_toplevel(mpWindow);
        GtkStyleContext* pStyle = gtk_widget_get_style_context(pTopLevel);
        gtk_style_context_set_parent(context, pStyle);
        gtk_style_context_set_scale (context, gtk_style_context_get_scale (pStyle));
    }
    else
    {
        gtk_style_context_set_parent(context, pParent);
        gtk_style_context_set_scale (context, gtk_style_context_get_scale (pParent));
    }
    gtk_widget_path_unref(pPath);
    return context;
}

GtkStyleContext* GtkSalGraphics::createStyleContext(GtkControlPart ePart)
{
    switch (ePart)
    {
        case GtkControlPart::ToplevelWindow:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "window");
            gtk_widget_path_iter_add_class(path, -1, "background");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::Button:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "button");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::LinkButton:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "button");
            gtk_widget_path_iter_add_class(path, -1, "link");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::CheckButton:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "checkbutton");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::CheckButtonCheck:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpCheckButtonStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "check");
            return makeContext(path, mpCheckButtonStyle);
        }
        case GtkControlPart::RadioButton:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "radiobutton");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::RadioButtonRadio:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpRadioButtonStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "radio");
            return makeContext(path, mpRadioButtonStyle);
        }
        case GtkControlPart::ComboboxBoxButtonBoxArrow:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpComboboxButtonBoxStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
            gtk_widget_path_append_type(path, GTK_TYPE_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "arrow");
            return makeContext(path, mpComboboxButtonBoxStyle);
        }
        case GtkControlPart::ListboxBoxButtonBoxArrow:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpListboxButtonBoxStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON);
            gtk_widget_path_append_type(path, GTK_TYPE_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "arrow");
            return makeContext(path, mpListboxButtonBoxStyle);
        }
        case GtkControlPart::Entry:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_ENTRY);
            gtk_widget_path_iter_set_object_name(path, -1, "entry");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::Combobox:
        case GtkControlPart::Listbox:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "combobox");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::ComboboxBox:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpComboboxStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "box");
            gtk_widget_path_iter_add_class(path, -1, "horizontal");
            gtk_widget_path_iter_add_class(path, -1, "linked");
            return makeContext(path, mpComboboxStyle);
        }
        case GtkControlPart::ListboxBox:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpListboxStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "box");
            gtk_widget_path_iter_add_class(path, -1, "horizontal");
            gtk_widget_path_iter_add_class(path, -1, "linked");
            return makeContext(path, mpListboxStyle);
        }
        case GtkControlPart::ComboboxBoxEntry:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpComboboxBoxStyle));
            GtkWidgetPath* pSiblingsPath;
            if (AllSettings::GetLayoutRTL())
            {
                pSiblingsPath = buildRTLComboSiblingsPath();
                gtk_widget_path_append_with_siblings(path, pSiblingsPath, 1);
            }
            else
            {
                pSiblingsPath = buildLTRComboSiblingsPath();
                gtk_widget_path_append_with_siblings(path, pSiblingsPath, 0);
            }
            gtk_widget_path_unref(pSiblingsPath);
            return makeContext(path, mpComboboxBoxStyle);
        }
        case GtkControlPart::ComboboxBoxButton:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpComboboxBoxStyle));
            GtkWidgetPath* pSiblingsPath;
            if (AllSettings::GetLayoutRTL())
            {
                pSiblingsPath = buildRTLComboSiblingsPath();
                gtk_widget_path_append_with_siblings(path, pSiblingsPath, 0);
            }
            else
            {
                pSiblingsPath = buildLTRComboSiblingsPath();
                gtk_widget_path_append_with_siblings(path, pSiblingsPath, 1);
            }
            gtk_widget_path_unref(pSiblingsPath);
            return makeContext(path, mpComboboxBoxStyle);
        }
        case GtkControlPart::ListboxBoxButton:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpListboxBoxStyle));
            GtkWidgetPath* pSiblingsPath = gtk_widget_path_new();

            gtk_widget_path_append_type(pSiblingsPath, GTK_TYPE_BUTTON);
            gtk_widget_path_iter_set_object_name(pSiblingsPath, -1, "button");
            gtk_widget_path_iter_add_class(pSiblingsPath, -1, "combo");

            gtk_widget_path_append_with_siblings(path, pSiblingsPath, 0);
            gtk_widget_path_unref(pSiblingsPath);
            return makeContext(path, mpListboxBoxStyle);
        }
        case GtkControlPart::ComboboxBoxButtonBox:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpComboboxButtonStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "box");
            gtk_widget_path_iter_add_class(path, -1, "horizontal");
            return makeContext(path, mpComboboxButtonStyle);
        }
        case GtkControlPart::ListboxBoxButtonBox:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpListboxButtonStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "box");
            gtk_widget_path_iter_add_class(path, -1, "horizontal");
            return makeContext(path, mpListboxButtonStyle);
        }
        case GtkControlPart::SpinButton:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpWindowStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_SPIN_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "spinbutton");
            gtk_widget_path_iter_add_class(path, -1, GTK_STYLE_CLASS_HORIZONTAL);
            return makeContext(path, mpWindowStyle);
        }
        case GtkControlPart::SpinButtonUpButton:
        case GtkControlPart::SpinButtonDownButton:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpSpinStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_SPIN_BUTTON);
            gtk_widget_path_iter_set_object_name(path, -1, "button");
            gtk_widget_path_iter_add_class(path, -1, ePart == GtkControlPart::SpinButtonUpButton "up" : "down");
            return makeContext(path, mpSpinStyle);
        }
        case GtkControlPart::ScrollbarVertical:
        case GtkControlPart::ScrollbarHorizontal:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_SCROLLBAR);
            gtk_widget_path_iter_set_object_name(path, -1, "scrollbar");
            gtk_widget_path_iter_add_class(path, -1, ePart == GtkControlPart::ScrollbarVertical ? "vertical" : "horizontal");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::ScrollbarVerticalContents:
        case GtkControlPart::ScrollbarHorizontalContents:
        {
            GtkStyleContext *pParent =
                (ePart == GtkControlPart::ScrollbarVerticalContents) ? mpVScrollbarStyle : mpHScrollbarStyle;
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(pParent));
            gtk_widget_path_append_type(path, GTK_TYPE_SCROLLBAR);
            gtk_widget_path_iter_set_object_name(path, -1, "contents");
            return makeContext(path, pParent);
        }
        case GtkControlPart::ScrollbarVerticalTrough:
        case GtkControlPart::ScrollbarHorizontalTrough:
        {
            GtkStyleContext *pParent =
                (ePart == GtkControlPart::ScrollbarVerticalTrough) ? mpVScrollbarContentsStyle : mpHScrollbarContentsStyle;
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(pParent));
            gtk_widget_path_append_type(path, GTK_TYPE_SCROLLBAR);
            gtk_widget_path_iter_set_object_name(path, -1, "trough");
            return makeContext(path, pParent);
        }
        case GtkControlPart::ScrollbarVerticalSlider:
        case GtkControlPart::ScrollbarHorizontalSlider:
        {
            GtkStyleContext *pParent =
                (ePart == GtkControlPart::ScrollbarVerticalSlider) ? mpVScrollbarTroughStyle : mpHScrollbarTroughStyle;
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(pParent));
            gtk_widget_path_append_type(path, GTK_TYPE_SCROLLBAR);
            gtk_widget_path_iter_set_object_name(path, -1, "slider");
            return makeContext(path, pParent);
        }
        case GtkControlPart::ScrollbarVerticalButton:
        case GtkControlPart::ScrollbarHorizontalButton:
        {
            GtkStyleContext *pParent =
                (ePart == GtkControlPart::ScrollbarVerticalButton) ? mpVScrollbarStyle : mpHScrollbarStyle;
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(pParent));
            gtk_widget_path_append_type(path, GTK_TYPE_SCROLLBAR);
            gtk_widget_path_iter_set_object_name(path, -1, "button");
            return makeContext(path, pParent);
        }
        case GtkControlPart::ProgressBar:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_PROGRESS_BAR);
            gtk_widget_path_iter_set_object_name(path, -1, "progressbar");
            gtk_widget_path_iter_add_class(path, -1, GTK_STYLE_CLASS_HORIZONTAL);
            return makeContext(path, nullptr);
        }
        case GtkControlPart::ProgressBarTrough:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpProgressBarStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_PROGRESS_BAR);
            gtk_widget_path_iter_set_object_name(path, -1, "trough");
            return makeContext(path, mpProgressBarStyle);
        }
        case GtkControlPart::ProgressBarProgress:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpProgressBarTroughStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_PROGRESS_BAR);
            gtk_widget_path_iter_set_object_name(path, -1, "progress");
            return makeContext(path, mpProgressBarTroughStyle);
        }
        case GtkControlPart::Notebook:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpWindowStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
            gtk_widget_path_iter_set_object_name(path, -1, "notebook");
            return makeContext(path, mpWindowStyle);
        }
        case GtkControlPart::NotebookStack:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpNotebookStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
            gtk_widget_path_iter_set_object_name(path, -1, "stack");
            return makeContext(path, mpNotebookStyle);
        }
        case GtkControlPart::NotebookHeader:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpNotebookStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
            gtk_widget_path_iter_set_object_name(path, -1, "header");
            gtk_widget_path_iter_add_class(path, -1, "frame");
            gtk_widget_path_iter_add_class(path, -1, "top");
            return makeContext(path, mpNotebookStyle);
        }
        case GtkControlPart::NotebookHeaderTabs:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpNotebookHeaderStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
            gtk_widget_path_iter_set_object_name(path, -1, "tabs");
            gtk_widget_path_iter_add_class(path, -1, "top");
            return makeContext(path, mpNotebookHeaderStyle);
        }
        case GtkControlPart::NotebookHeaderTabsTab:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpNotebookHeaderTabsStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_NOTEBOOK);
            gtk_widget_path_iter_set_object_name(path, -1, "tab");
            gtk_widget_path_iter_add_class(path, -1, "top");
            return makeContext(path, mpNotebookHeaderTabsStyle);
        }
        case GtkControlPart::NotebookHeaderTabsTabLabel:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpNotebookHeaderTabsTabStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "label");
            return makeContext(path, mpNotebookHeaderTabsTabStyle);
        }
        case GtkControlPart::NotebookHeaderTabsTabActiveLabel:
        case GtkControlPart::NotebookHeaderTabsTabHoverLabel:
            return mpNotebookHeaderTabsTabLabelStyle;
        case GtkControlPart::FrameBorder:
        {
            GtkWidgetPath *path = gtk_widget_path_new();
            gtk_widget_path_append_type(path, GTK_TYPE_FRAME);
            gtk_widget_path_iter_set_object_name(path, -1, "frame");
            gtk_widget_path_iter_add_class(path, -1, "frame");
            return makeContext(path, nullptr);
        }
        case GtkControlPart::MenuBar:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpWindowStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_MENU_BAR);
            gtk_widget_path_iter_set_object_name(path, -1, "menubar");
            gtk_widget_path_iter_add_class(path, -1, "background");
            return makeContext(path, mpWindowStyle);
        }
        case GtkControlPart::MenuBarItem:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuBarStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "menuitem");
            return makeContext(path, mpMenuBarStyle);
        }
        case GtkControlPart::MenuWindow:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuBarItemStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "window");
            gtk_widget_path_iter_add_class(path, -1, "background");
            gtk_widget_path_iter_add_class(path, -1, "popup");
            return makeContext(path, mpMenuBarItemStyle);
        }
        case GtkControlPart::Menu:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuWindowStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_MENU);
            gtk_widget_path_iter_set_object_name(path, -1, "menu");
            return makeContext(path, mpMenuWindowStyle);
        }
        case GtkControlPart::MenuItem:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "menuitem");
            return makeContext(path, mpMenuStyle);
        }
        case GtkControlPart::MenuItemLabel:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuItemStyle));
            gtk_widget_path_append_type(path, G_TYPE_NONE);
            gtk_widget_path_iter_set_object_name(path, -1, "label");
            return makeContext(path, mpMenuItemStyle);
        }
        case GtkControlPart::MenuItemArrow:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuItemStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "arrow");
            return makeContext(path, mpMenuItemStyle);
        }
        case GtkControlPart::CheckMenuItem:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_CHECK_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "menuitem");
            return makeContext(path, mpMenuStyle);
        }
        case GtkControlPart::CheckMenuItemCheck:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpCheckMenuItemStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_CHECK_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "check");
            return makeContext(path, mpCheckMenuItemStyle);
        }
        case GtkControlPart::RadioMenuItem:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "menuitem");
            return makeContext(path, mpMenuStyle);
        }
        case GtkControlPart::RadioMenuItemRadio:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpRadioMenuItemStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_RADIO_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "radio");
            return makeContext(path, mpRadioMenuItemStyle);
        }
        case GtkControlPart::SeparatorMenuItem:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpMenuStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_SEPARATOR_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "menuitem");
            return makeContext(path, mpMenuStyle);
        }
        case GtkControlPart::SeparatorMenuItemSeparator:
        {
            GtkWidgetPath *path = gtk_widget_path_copy(gtk_style_context_get_path(mpSeparatorMenuItemStyle));
            gtk_widget_path_append_type(path, GTK_TYPE_SEPARATOR_MENU_ITEM);
            gtk_widget_path_iter_set_object_name(path, -1, "separator");
            return makeContext(path, mpSeparatorMenuItemStyle);
        }
    }

    return nullptr;
}

#ifndef GTK_STYLE_CLASS_POPUP
constexpr OUStringLiteral GTK_STYLE_CLASS_POPUP = u"popup";
#endif
#ifndef GTK_STYLE_CLASS_LABEL
constexpr OUStringLiteral GTK_STYLE_CLASS_LABEL = u"label";
#endif

void GtkSalGraphics::PaintCheckOrRadio(cairo_t *cr, GtkStyleContext *context,
                                       const tools::Rectangle& rControlRectangle, bool bIsCheck, bool bInMenu)
{
    gint indicator_size;
    gtk_style_context_get_style(context, "indicator-size", &indicator_size, nullptr);

    gint x = (rControlRectangle.GetWidth() - indicator_size) / 2;
    gint y = (rControlRectangle.GetHeight() - indicator_size) / 2;

    if (!bInMenu)
        gtk_render_background(context, cr, x, y, indicator_size, indicator_size);

    if (bIsCheck)
--> --------------------

--> maximum size reached

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

Messung V0.5
C=97 H=93 G=94

¤ Dauer der Verarbeitung: 0.13 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.