/**************************************************************
 * 
 * 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
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include "vcl/svapp.hxx"

#include "unx/gtk/gtkframe.hxx"
#include "unx/gtk/gtkdata.hxx"
#include "unx/gtk/gtkinst.hxx"
#include "unx/gtk/gtkgdi.hxx"

#include "unx/pspgraphics.h"
#include "unx/saldata.hxx"
#include "unx/saldisp.hxx"

#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <hash_map>

typedef struct _cairo_font_options cairo_font_options_t;

// initialize statics
sal_Bool GtkSalGraphics::bThemeChanged = sal_True;
sal_Bool GtkSalGraphics::bNeedPixmapPaint = sal_False;
sal_Bool GtkSalGraphics::bGlobalNeedPixmapPaint = sal_False;
sal_Bool GtkSalGraphics::bToolbarGripWorkaround = sal_False;
sal_Bool GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = sal_False;

GtkSalGraphics::~GtkSalGraphics()
{
}


using namespace rtl;

/*************************************
 * Cached native widget objects
 *************************************/
class NWPixmapCacheList;
class NWPixmapCache;
struct NWFWidgetData
{
    GtkWidget *	gCacheWindow;
    GtkWidget *	gDumbContainer;

    GtkWidget *	gBtnWidget;
    GtkWidget *	gRadioWidget;
    GtkWidget *	gRadioWidgetSibling;
    GtkWidget *	gCheckWidget;
    GtkWidget *	gScrollHorizWidget;
    GtkWidget *	gScrollVertWidget;
    GtkWidget *	gArrowWidget;
    GtkWidget *	gDropdownWidget;
    GtkWidget *	gEditBoxWidget;
    GtkWidget *	gSpinButtonWidget;
    GtkWidget *	gNotebookWidget;
    GtkWidget *	gOptionMenuWidget;
    GtkWidget *	gComboWidget;
    GtkWidget *	gScrolledWindowWidget;
    GtkWidget *  gToolbarWidget;
    GtkWidget *  gToolbarButtonWidget;
    GtkWidget *  gToolbarToggleWidget;
    GtkWidget *  gHandleBoxWidget;
    GtkWidget *  gMenubarWidget;
    GtkWidget *  gMenuItemMenubarWidget;
    GtkWidget *  gMenuWidget;
    GtkWidget *  gMenuItemMenuWidget;
    GtkWidget *  gMenuItemCheckMenuWidget;
    GtkWidget *  gMenuItemRadioMenuWidget;
    GtkWidget *  gImageMenuItem;
    GtkWidget *  gTooltipPopup;
    GtkWidget *  gProgressBar;
    GtkWidget *  gTreeView;
    GtkWidget *  gHScale;
    GtkWidget *  gVScale;

    NWPixmapCacheList* gNWPixmapCacheList;
    NWPixmapCache* gCacheTabItems;
    NWPixmapCache* gCacheTabPages;
    
    NWFWidgetData() :
        gCacheWindow( NULL ),
        gDumbContainer( NULL ),
        gBtnWidget( NULL ),
        gRadioWidget( NULL ),
        gRadioWidgetSibling( NULL ),
        gCheckWidget( NULL ),
        gScrollHorizWidget( NULL ),
        gScrollVertWidget( NULL ),
        gArrowWidget( NULL ),
        gDropdownWidget( NULL ),
        gEditBoxWidget( NULL ),
        gSpinButtonWidget( NULL ),
        gNotebookWidget( NULL ),
        gOptionMenuWidget( NULL ),
        gComboWidget( NULL ),
        gScrolledWindowWidget( NULL ),
        gToolbarWidget( NULL ),
        gToolbarButtonWidget( NULL ),
        gToolbarToggleWidget( NULL ),
        gHandleBoxWidget( NULL ),
        gMenubarWidget( NULL ),
        gMenuItemMenubarWidget( NULL ),
        gMenuWidget( NULL ),
        gMenuItemMenuWidget( NULL ),
        gMenuItemCheckMenuWidget( NULL ),
        gMenuItemRadioMenuWidget( NULL ),
        gImageMenuItem( NULL ),
        gTooltipPopup( NULL ),
        gProgressBar( NULL ),
        gTreeView( NULL ),
        gHScale( NULL ),
        gVScale( NULL ),
        gNWPixmapCacheList( NULL ),
        gCacheTabItems( NULL ),
        gCacheTabPages( NULL )
    {}
};

// Keep a hash table of Widgets->default flags so that we can
// easily and quickly reset each to a default state before using
// them
static std::hash_map<long, guint>	gWidgetDefaultFlags;
static std::vector<NWFWidgetData>   gWidgetData;

static const GtkBorder aDefDefBorder		= { 1, 1, 1, 1 };

// Some GTK defaults
#define MIN_ARROW_SIZE					11
#define BTN_CHILD_SPACING				1
#define MIN_SPIN_ARROW_WIDTH				6


static void NWEnsureGTKRadio			( int nScreen );
static void NWEnsureGTKButton			( int nScreen );
static void NWEnsureGTKCheck			( int nScreen );
static void NWEnsureGTKScrollbars		( int nScreen );
static void NWEnsureGTKArrow			( int nScreen );
static void NWEnsureGTKEditBox			( int nScreen );
static void NWEnsureGTKSpinButton		( int nScreen );
static void NWEnsureGTKNotebook			( int nScreen );
static void NWEnsureGTKOptionMenu		( int nScreen );
static void NWEnsureGTKCombo			( int nScreen );
static void NWEnsureGTKScrolledWindow	( int nScreen );
static void NWEnsureGTKToolbar			( int nScreen );
static void NWEnsureGTKMenubar          ( int nScreen );
static void NWEnsureGTKMenu             ( int nScreen );
static void NWEnsureGTKTooltip          ( int nScreen );
static void NWEnsureGTKProgressBar      ( int nScreen );
static void NWEnsureGTKTreeView         ( int nScreen );
static void NWEnsureGTKSlider           ( int nScreen );

static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen );
static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );

static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );

/*
 * Individual helper functions
 *
 */

//---
static Rectangle NWGetButtonArea( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
								const ImplControlValue& aValue, const OUString& rCaption );

//---
static Rectangle NWGetEditBoxPixmapRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
							const ImplControlValue& aValue, const OUString& rCaption );

static void NWPaintOneEditBox( int nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect, 
                               ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
                               ControlState nState, const ImplControlValue& aValue,
                               const OUString& rCaption );

//---
static Rectangle NWGetSpinButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
							const ImplControlValue& aValue, const OUString& rCaption );

static void NWPaintOneSpinButton( int nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
							ControlState nState, const ImplControlValue& aValue,
							const OUString& rCaption );
//---
static Rectangle NWGetComboBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
							const ImplControlValue& aValue, const OUString& rCaption );

//---
static Rectangle NWGetListBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
							const ImplControlValue& aValue, const OUString& rCaption );

static Rectangle NWGetListBoxIndicatorRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
							const ImplControlValue& aValue, const OUString& rCaption );

static Rectangle NWGetToolbarRect( int nScreen,
                                   ControlType nType,
                                   ControlPart nPart,
                                   Rectangle aAreaRect,
                                   ControlState nState,
                                   const ImplControlValue& aValue,
                                   const OUString& rCaption );
//---

static Rectangle NWGetScrollButtonRect(	int nScreen, ControlPart nPart, Rectangle aAreaRect );
//---
								
/*********************************************************
 * PixmapCache
 *********************************************************/

// as some native widget drawing operations are pretty slow
// with certain themes (eg tabpages)
// this cache can be used to cache the corresponding pixmap
// see NWPaintGTKTabItem

class NWPixmapCacheData
{
public:
    ControlType m_nType;
    ControlState m_nState;
    Rectangle   m_pixmapRect;
    GdkPixmap*  m_pixmap;
    
    NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {}
    ~NWPixmapCacheData()
        { SetPixmap( NULL ); };
    void SetPixmap( GdkPixmap* pPixmap );
};

class NWPixmapCache
{
    int m_size;
    int m_idx;
    int m_screen;
    NWPixmapCacheData* pData;
public:
    NWPixmapCache( int nScreen );
    ~NWPixmapCache();
    
    void SetSize( int n)
        { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
    int GetSize() { return m_size; }
    
    sal_Bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap );
    void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap );
    
    void ThemeChanged();    
};

class NWPixmapCacheList
{
public:
    ::std::vector< NWPixmapCache* > mCaches;

    void AddCache( NWPixmapCache *pCache );
    void RemoveCache( NWPixmapCache *pCache );
    void ThemeChanged();
};

// --- implementation ---

void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap )
{
    if( m_pixmap )
        g_object_unref( m_pixmap );
    
    m_pixmap = pPixmap;
    
    if( m_pixmap )
        g_object_ref( m_pixmap );
}


NWPixmapCache::NWPixmapCache( int nScreen )
{
    m_idx = 0;
    m_size = 0;
    m_screen = nScreen;
    pData = NULL;
    if( gWidgetData[m_screen].gNWPixmapCacheList )
        gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
} 
NWPixmapCache::~NWPixmapCache()
{
    if( gWidgetData[m_screen].gNWPixmapCacheList )
        gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
    delete[] pData;
}
void NWPixmapCache::ThemeChanged()
{
    // throw away cached pixmaps
    int i;
    for(i=0; i<m_size; i++)
        pData[i].SetPixmap( NULL );
}

sal_Bool  NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap )
{
    aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
    int i;
    for(i=0; i<m_size; i++)
    {
        if( pData[i].m_nType == aType &&
            pData[i].m_nState == aState &&    
            pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&    
            pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&    
            pData[i].m_pixmap != NULL )
        {
            *pPixmap = pData[i].m_pixmap;
            return sal_True;
        }
    }
    return sal_False;
}

void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap )
{
    if( !(aState & CTRL_CACHING_ALLOWED) )
        return; 

    aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
    m_idx = (m_idx+1) % m_size; // just wrap
    pData[m_idx].m_nType = aType;
    pData[m_idx].m_nState = aState;
    pData[m_idx].m_pixmapRect = r_pixmapRect;
    pData[m_idx].SetPixmap( pPixmap );
}


void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
{
    mCaches.push_back( pCache );
}
void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
{
    ::std::vector< NWPixmapCache* >::iterator p;
    p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
    if( p != mCaches.end() )
        mCaches.erase( p );
}
void NWPixmapCacheList::ThemeChanged( )
{
    ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
    while( p != mCaches.end() )
    {
        (*p)->ThemeChanged();
        p++;
    }
}


/*********************************************************
 * Make border manipulation easier
 *********************************************************/
inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
{
	aDst.left		= pSrc->left;
	aDst.top		= pSrc->top;
	aDst.right	= pSrc->right;
	aDst.bottom	= pSrc->bottom;
}


/*********************************************************
 * Initialize GTK and local stuff                         
 *********************************************************/
void GtkData::initNWF( void )
{
    ImplSVData* pSVData = ImplGetSVData();

    // draw no border for popup menus (NWF draws its own)
    pSVData->maNWFData.mbFlatMenu = true;

    // draw separate buttons for toolbox dropdown items
    pSVData->maNWFData.mbToolboxDropDownSeparate = true;
    
    // small extra border around menu items
    pSVData->maNWFData.mnMenuFormatExtraBorder = 1;
    
    // draw toolbars in separate lines
    pSVData->maNWFData.mbDockingAreaSeparateTB = true;
    
    // open first menu on F10
    pSVData->maNWFData.mbOpenMenuOnF10 = true;
    
    // omit GetNativeControl while painting (see brdwin.cxx)
    pSVData->maNWFData.mbCanDrawWidgetAnySize = true;
    
    int nScreens = GetX11SalData()->GetDisplay()->GetScreenCount();
    gWidgetData = std::vector<NWFWidgetData>( nScreens );
    for( int i = 0; i < nScreens; i++ )
        gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;

    
    if( SalGetDesktopEnvironment().equalsAscii( "KDE" ) )
    {
        // #i97196# ensure a widget exists and the style engine was loaded
        NWEnsureGTKButton( 0 );
        if( g_type_from_name( "QtEngineStyle" ) )
        {
            // KDE 3.3 invented a bug in the qt<->gtk theme engine
            // that makes direct rendering impossible: they totally
            // ignore the clip rectangle passed to the paint methods
            GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
        }
    }
    static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
    if( pEnv && *pEnv )
        GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;

    #if OSL_DEBUG_LEVEL > 1
    std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
             GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
    #endif
}


/*********************************************************
 * Release GTK and local stuff                         
 *********************************************************/
void GtkData::deInitNWF( void )
{

    for( unsigned int i = 0; i < gWidgetData.size(); i++ )
    {
        // free up global widgets
        // gtk_widget_destroy will in turn destroy the child hierarchy
        // so only destroy disjunct hierachies
        if( gWidgetData[i].gCacheWindow )
            gtk_widget_destroy( gWidgetData[i].gCacheWindow );
        if( gWidgetData[i].gMenuWidget )
            gtk_widget_destroy( gWidgetData[i].gMenuWidget );
        if( gWidgetData[i].gTooltipPopup )
            gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
        delete gWidgetData[i].gCacheTabPages;
        gWidgetData[i].gCacheTabPages = NULL;
        delete gWidgetData[i].gCacheTabItems;
        gWidgetData[i].gCacheTabItems = NULL;
        delete gWidgetData[i].gNWPixmapCacheList;
        gWidgetData[i].gNWPixmapCacheList = NULL;
    }
}


/**********************************************************
 * track clip region
 **********************************************************/
void GtkSalGraphics::ResetClipRegion()
{
    m_aClipRegion.SetNull();
    X11SalGraphics::ResetClipRegion();
}

bool GtkSalGraphics::setClipRegion( const Region& i_rClip )
{
    m_aClipRegion = i_rClip;
    bool bRet = X11SalGraphics::setClipRegion( m_aClipRegion );
    if( m_aClipRegion.IsEmpty() )
        m_aClipRegion.SetNull();
    return bRet;
}

void GtkSalGraphics::copyBits( const SalTwoRect& rPosAry,
                               SalGraphics* pSrcGraphics )
{
    GtkSalFrame* pFrame = GetGtkFrame();
    XLIB_Window aWin = None;
    if( pFrame && m_pWindow )
    {
        /* #i64117# some themes set the background pixmap VERY frequently */
        GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
        if( pWin )
        {
            aWin = GDK_WINDOW_XWINDOW(pWin);
            if( aWin != None )
                XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
                                            aWin,
                                            None );
        }
    }
    X11SalGraphics::copyBits( rPosAry, pSrcGraphics );
    if( pFrame && pFrame->getBackgroundPixmap() != None )
        XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
                                    aWin,
                                    pFrame->getBackgroundPixmap() );
}

/*
 * IsNativeControlSupported()
 *
 *  Returns sal_True if the platform supports native
 *  drawing of the control defined by nPart
 */
sal_Bool GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
{
	if (
		((nType==CTRL_PUSHBUTTON)  && (nPart==PART_ENTIRE_CONTROL)) 	||
 		((nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL))		||
		((nType==CTRL_CHECKBOX)    && (nPart==PART_ENTIRE_CONTROL))		||
		((nType==CTRL_SCROLLBAR) &&
				(  (nPart==PART_DRAW_BACKGROUND_HORZ)
				|| (nPart==PART_DRAW_BACKGROUND_VERT)
				|| (nPart==PART_ENTIRE_CONTROL)
                || (nPart==HAS_THREE_BUTTONS) )  				)	||
		((nType==CTRL_EDITBOX) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==HAS_BACKGROUND_TEXTURE) ) 			)	||
		((nType==CTRL_MULTILINE_EDITBOX) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==HAS_BACKGROUND_TEXTURE) ) 			)	||
		((nType==CTRL_SPINBOX) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==PART_ALL_BUTTONS)
				|| (nPart==HAS_BACKGROUND_TEXTURE) )			)	||
		((nType==CTRL_SPINBUTTONS) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==PART_ALL_BUTTONS)	)				)	||
		((nType==CTRL_COMBOBOX) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==HAS_BACKGROUND_TEXTURE)	)			)	||
		(((nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) ||
		  (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER)) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==PART_TABS_DRAW_RTL) )				)	||
		((nType==CTRL_LISTBOX) &&
				(  (nPart==PART_ENTIRE_CONTROL)
				|| (nPart==PART_WINDOW)
				|| (nPart==HAS_BACKGROUND_TEXTURE) )			)   ||
        ((nType == CTRL_TOOLBAR) &&
         		(	(nPart==PART_ENTIRE_CONTROL)
                ||  (nPart==PART_DRAW_BACKGROUND_HORZ)
                ||  (nPart==PART_DRAW_BACKGROUND_VERT)
                ||  (nPart==PART_THUMB_HORZ)
                ||  (nPart==PART_THUMB_VERT)
                ||  (nPart==PART_BUTTON)
                )
                                                                )   ||
        ((nType == CTRL_MENUBAR) &&
                (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
        ((nType == CTRL_TOOLTIP) &&
                (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
        ((nType == CTRL_MENU_POPUP) &&
                (   (nPart==PART_ENTIRE_CONTROL)
                ||  (nPart==PART_MENU_ITEM)
                ||  (nPart==PART_MENU_ITEM_CHECK_MARK)
                ||  (nPart==PART_MENU_ITEM_RADIO_MARK)
                )
                                                                )   ||
        ((nType == CTRL_PROGRESS) &&
                (   (nPart == PART_ENTIRE_CONTROL) )
                )                                                   ||
        ((nType == CTRL_LISTNODE || nType == CTRL_LISTNET) &&
                (   (nPart == PART_ENTIRE_CONTROL) )
                )                                                   ||
        ((nType == CTRL_SLIDER) &&
                (   (nPart == PART_TRACK_HORZ_AREA)
                ||  (nPart == PART_TRACK_VERT_AREA)
                )
        )
        )
		return( sal_True );

	return( sal_False );
}


/*
 * HitTestNativeControl()
 *
 *  bIsInside is set to sal_True if aPos is contained within the
 *  given part of the control, whose bounding region is
 *  given by rControlRegion (in VCL frame coordinates).
 *
 *  returns whether bIsInside was really set.
 */
sal_Bool GtkSalGraphics::hitTestNativeControl( ControlType		nType,
								ControlPart		nPart,
								const Rectangle&		rControlRegion,
								const Point&		aPos,
								sal_Bool&			rIsInside )
{
    if ( ( nType == CTRL_SCROLLBAR ) &&
         ( ( nPart == PART_BUTTON_UP ) ||
           ( nPart == PART_BUTTON_DOWN ) ||
           ( nPart == PART_BUTTON_LEFT ) ||
           ( nPart == PART_BUTTON_RIGHT ) ) )
    {
        NWEnsureGTKScrollbars( m_nScreen );

        // Grab some button style attributes
        gboolean has_forward;
        gboolean has_forward2;
        gboolean has_backward;
        gboolean has_backward2;
        
	    gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
									    "has-secondary-forward-stepper", &has_forward2,
									    "has-backward-stepper", &has_backward,
	   								    "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
        Rectangle aForward;
        Rectangle aBackward;

        rIsInside = sal_False;

        ControlPart nCounterPart = 0;
        if ( nPart == PART_BUTTON_UP )
            nCounterPart = PART_BUTTON_DOWN;
        else if ( nPart == PART_BUTTON_DOWN )
            nCounterPart = PART_BUTTON_UP;
        else if ( nPart == PART_BUTTON_LEFT )
            nCounterPart = PART_BUTTON_RIGHT;
        else if ( nPart == PART_BUTTON_RIGHT )
            nCounterPart = PART_BUTTON_LEFT;

        aBackward = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
        aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion );

        if ( has_backward && has_forward2 )
        {
            Size aSize( aBackward.GetSize() );
            if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
                aSize.setHeight( aBackward.GetHeight() / 2 );
            else
                aSize.setWidth( aBackward.GetWidth() / 2 );
            aBackward.SetSize( aSize );

            if ( nPart == PART_BUTTON_DOWN )
                aBackward.Move( 0, aBackward.GetHeight() / 2 );
            else if ( nPart == PART_BUTTON_RIGHT )
                aBackward.Move( aBackward.GetWidth() / 2, 0 );
        }

        if ( has_backward2 && has_forward )
        {
            Size aSize( aForward.GetSize() );
            if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
                aSize.setHeight( aForward.GetHeight() / 2 );
            else
                aSize.setWidth( aForward.GetWidth() / 2 );
            aForward.SetSize( aSize );

            if ( nPart == PART_BUTTON_DOWN )
                aForward.Move( 0, aForward.GetHeight() / 2 );
            else if ( nPart == PART_BUTTON_RIGHT )
                aForward.Move( aForward.GetWidth() / 2, 0 );
        }

        if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
        {
            if ( has_backward )
                rIsInside |= aBackward.IsInside( aPos );
            if ( has_backward2 )
                rIsInside |= aForward.IsInside( aPos );
        }
        else
        {
            if ( has_forward )
                rIsInside |= aBackward.IsInside( aPos );
            if ( has_forward2 )
                rIsInside |= aForward.IsInside( aPos );
        }
        return ( sal_True );
    }

    if( IsNativeControlSupported(nType, nPart) )
	{
		rIsInside = rControlRegion.IsInside( aPos );
		return( sal_True );
	}
	else
	{
		return( sal_False );
	}
}


/*
 * DrawNativeControl()
 *
 *  Draws the requested control described by nPart/nState.
 *
 *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
 *  aValue:  		An optional value (tristate/numerical/string)
 *  rCaption:  	A caption or title string (like button text etc)
 */
sal_Bool GtkSalGraphics::drawNativeControl(	ControlType nType,
							ControlPart nPart,
							const Rectangle& rControlRegion,
							ControlState nState,
							const ImplControlValue& aValue,
							const OUString& rCaption )
{
	sal_Bool			returnVal = sal_False;
	// get a GC with current clipping region set
    GetFontGC();
    
    
    // theme changed ?
    if( GtkSalGraphics::bThemeChanged )
    {
        // invalidate caches
        for( unsigned int i = 0; i < gWidgetData.size(); i++ )
            if( gWidgetData[i].gNWPixmapCacheList )
                gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
        GtkSalGraphics::bThemeChanged = sal_False;    
    }
    
    Rectangle aCtrlRect( rControlRegion );
    Region aClipRegion( m_aClipRegion );
    if( aClipRegion.IsNull() )
        aClipRegion = aCtrlRect;
            
    clipList aClip;        
    GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() );
    GdkPixmap* pixmap = NULL;
    Rectangle aPixmapRect;
    if( ( bNeedPixmapPaint )
        && nType != CTRL_SCROLLBAR
        && nType != CTRL_SPINBOX
        && nType != CTRL_TAB_ITEM
        && nType != CTRL_TAB_PANE
        && nType != CTRL_PROGRESS
        && ! (bToolbarGripWorkaround && nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
        ) 
    {
        // make pixmap a little larger since some themes draw decoration
        // outside the rectangle, see e.g. checkbox
        aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
                                 Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
        pixmap = NWGetPixmapFromScreen( aPixmapRect );
        if( ! pixmap )
            return sal_False;
        gdkDrawable = GDK_DRAWABLE( pixmap );
        aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
        aClip.push_back( aCtrlRect );
    }
    else
    {
        RectangleVector aRectangles;
        aClipRegion.GetRegionRectangles(aRectangles);

        for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
        {
            if(aRectIter->IsEmpty())
            {
                continue;
            }

            aClip.push_back(*aRectIter);
        }

        //RegionHandle aHdl = aClipRegion.BeginEnumRects();
        //Rectangle aPaintRect;
        //while( aClipRegion.GetEnumRects( aHdl, aPaintRect ) )
        //{
        //    aPaintRect = aCtrlRect.GetIntersection( aPaintRect );
        //    if( aPaintRect.IsEmpty() )
        //        continue;
        //    aClip.push_back( aPaintRect );
        //}
        //aClipRegion.EndEnumRects( aHdl );
    }
    
    if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKButton( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKRadio( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKCheck( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
    {
        returnVal = NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
        || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
    || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
    || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
    {
        returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
    {
        returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
        && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
    {
        returnVal = NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType == CTRL_COMBOBOX) &&
        ( (nPart==PART_ENTIRE_CONTROL)
        ||(nPart==PART_BUTTON_DOWN)
        ) )
    {
        returnVal = NWPaintGTKComboBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER) )
    {
        if ( nType == CTRL_TAB_BODY )
            returnVal = sal_True;
        else
            returnVal = NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
    }
    else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
    {
        returnVal = NWPaintGTKListBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType== CTRL_TOOLBAR) )
    {
        returnVal = NWPaintGTKToolbar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if ( (nType== CTRL_MENUBAR) )
    {
        returnVal = NWPaintGTKMenubar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if(    (nType == CTRL_MENU_POPUP)
        && (  (nPart == PART_ENTIRE_CONTROL)
    || (nPart == PART_MENU_ITEM)
    || (nPart == PART_MENU_ITEM_CHECK_MARK)
    || (nPart == PART_MENU_ITEM_RADIO_MARK)
    )
    )
    {
        returnVal = NWPaintGTKPopupMenu( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKTooltip( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKProgress( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
    {
        returnVal = NWPaintGTKListNode( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
    {
        // don't actually draw anything; gtk treeviews do not draw lines
        returnVal = true;
    }
    else if( (nType == CTRL_SLIDER) )
    {
        returnVal = NWPaintGTKSlider( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
    }
    
    if( pixmap )
    {
        returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal;
        g_object_unref( pixmap );
    }

	return( returnVal );
}

/*
 * DrawNativeControlText()
 *
 *  OPTIONAL.  Draws the requested text for the control described by nPart/nState.
 *     Used if text not drawn by DrawNativeControl().
 *
 *  rControlRegion:	The bounding region of the complete control in VCL frame coordinates.
 *  aValue:  		An optional value (tristate/numerical/string)
 *  rCaption:  	A caption or title string (like button text etc)
 */
sal_Bool GtkSalGraphics::drawNativeControlText(	ControlType,
								ControlPart,
								const Rectangle&,
								ControlState,
								const ImplControlValue&,
								const OUString& )
{
	return( sal_False );
}


/*
 * GetNativeControlRegion()
 *
 *  If the return value is sal_True, rNativeBoundingRegion
 *  contains the true bounding region covered by the control
 *  including any adornment, while rNativeContentRegion contains the area
 *  within the control that can be safely drawn into without drawing over
 *  the borders of the control.
 *
 *  rControlRegion:	The bounding region of the control in VCL frame coordinates.
 *  aValue:		An optional value (tristate/numerical/string)
 *  rCaption:		A caption or title string (like button text etc)
 */
sal_Bool GtkSalGraphics::getNativeControlRegion(  ControlType nType,
								ControlPart nPart,
								const Rectangle& rControlRegion,
								ControlState nState,
								const ImplControlValue& aValue,
								const OUString& rCaption,
								Rectangle &rNativeBoundingRegion,
								Rectangle &rNativeContentRegion )
{
	sal_Bool returnVal = sal_False;

    if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
        && (rControlRegion.GetWidth() > 16)
    && (rControlRegion.GetHeight() > 16) )
    {
        rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion,
        nState, aValue, rCaption );
        rNativeContentRegion = rControlRegion;
        
        returnVal = sal_True;
    }
    if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
    {
        rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
        aValue, rCaption );
        rNativeContentRegion = rNativeBoundingRegion;
        
        returnVal = sal_True;
    }
    if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
    {
        
        rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
        aValue, rCaption );
        rNativeContentRegion = rNativeBoundingRegion;
        
        returnVal = sal_True;
    }
    if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
    {
        rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
        aValue, rCaption );
        rNativeContentRegion = rNativeBoundingRegion;
        
        returnVal = sal_True;
    }
    if ( (nType==CTRL_TOOLBAR) &&
        ((nPart==PART_DRAW_BACKGROUND_HORZ)	||
        (nPart==PART_DRAW_BACKGROUND_VERT)	||
        (nPart==PART_THUMB_HORZ)			||
        (nPart==PART_THUMB_VERT)            ||
        (nPart==PART_BUTTON)
        ))
    {
        rNativeBoundingRegion = NWGetToolbarRect( m_nScreen, nType, nPart, rControlRegion, nState, aValue, rCaption );
        rNativeContentRegion = rNativeBoundingRegion;
        returnVal = sal_True;
    }
    if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
        (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN)  ) )
    {
        rNativeBoundingRegion = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
        rNativeContentRegion = rNativeBoundingRegion;
        
        returnVal = sal_True;
    }
    if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
    {
        NWEnsureGTKMenubar( m_nScreen );
        GtkRequisition aReq;
        gtk_widget_size_request( gWidgetData[m_nScreen].gMenubarWidget, &aReq );
        Rectangle aMenuBarRect = rControlRegion;
        aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
                                  Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
        rNativeBoundingRegion = aMenuBarRect;
        rNativeContentRegion = rNativeBoundingRegion;
        returnVal = sal_True;
    }
    if( (nType == CTRL_MENU_POPUP) )
    {
        if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
            (nPart == PART_MENU_ITEM_RADIO_MARK) )
        {
            NWEnsureGTKMenu( m_nScreen );

            gint indicator_size = 0;
            GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
                                 gWidgetData[m_nScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
            gtk_widget_style_get( pWidget,
                                  "indicator_size", &indicator_size,
                                  (char *)NULL );
            rNativeBoundingRegion = rControlRegion;
            Rectangle aIndicatorRect( Point( 0,
                                             (rControlRegion.GetHeight()-indicator_size)/2),
                                      Size( indicator_size, indicator_size ) );
            rNativeContentRegion = aIndicatorRect;
            returnVal = sal_True;
        }
    }
    if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
    {
        NWEnsureGTKRadio( m_nScreen );
        NWEnsureGTKCheck( m_nScreen );
        GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nScreen].gRadioWidget : gWidgetData[m_nScreen].gCheckWidget;
        gint indicator_size, indicator_spacing;
        gtk_widget_style_get( widget,
                              "indicator_size", &indicator_size,
                              "indicator_spacing", &indicator_spacing,
                              (char *)NULL);
        indicator_size += 2*indicator_spacing; // guess overpaint of theme
        rNativeBoundingRegion = rControlRegion;
        Rectangle aIndicatorRect( Point( 0,
                                         (rControlRegion.GetHeight()-indicator_size)/2),
                                  Size( indicator_size, indicator_size ) );
        rNativeContentRegion = aIndicatorRect;
        returnVal = sal_True;
    }
    if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
    {
        NWEnsureGTKEditBox( m_nScreen );
        GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget;
        GtkRequisition aReq;
        gtk_widget_size_request( widget, &aReq );
        Rectangle aEditRect = rControlRegion;
        long nHeight = (aEditRect.GetHeight() > aReq.height+1) ? aEditRect.GetHeight() : aReq.height+1; 
        aEditRect = Rectangle( aEditRect.TopLeft(),
                               Size( aEditRect.GetWidth(), nHeight ) );
        rNativeBoundingRegion = aEditRect;
        rNativeContentRegion = rNativeBoundingRegion;
        returnVal = sal_True;
    }
    if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
    {
        NWEnsureGTKSlider( m_nScreen );
        GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nScreen].gHScale : gWidgetData[m_nScreen].gVScale;
        gint slider_length = 10;
        gint slider_width = 10;
        gtk_widget_style_get( widget,
                              "slider-width", &slider_width,
                              "slider-length", &slider_length,
                              (char *)NULL);
        Rectangle aRect( rControlRegion );
        if( nPart == PART_THUMB_HORZ )
        {
            aRect.Right() = aRect.Left() + slider_length - 1;
            aRect.Bottom() = aRect.Top() + slider_width - 1;
        }
        else
        {
            aRect.Bottom() = aRect.Top() + slider_length - 1;
            aRect.Right() = aRect.Left() + slider_width - 1;
        }
        rNativeBoundingRegion = rNativeContentRegion = aRect;
        returnVal = sal_True;
    }
        
	return( returnVal );
}


/************************************************************************
 * Individual control drawing functions
 ************************************************************************/
sal_Bool GtkSalGraphics::NWPaintGTKButton(
            GdkDrawable* gdkDrawable,
            ControlType, ControlPart,
			const Rectangle& rControlRectangle,            
            const clipList& rClipList,
            ControlState nState, const ImplControlValue&,
			const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	gboolean		interiorFocus;
	gint			focusWidth;
	gint			focusPad;
	sal_Bool			bDrawFocus = sal_True;
	gint			x, y, w, h;
	GtkBorder		aDefBorder;
	GtkBorder*		pBorder;
    GdkRectangle	clipRect;
    
	NWEnsureGTKButton( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

	x = rControlRectangle.Left();
    y = rControlRectangle.Top();
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

	// Grab some button style attributes
	gtk_widget_style_get( gWidgetData[m_nScreen].gBtnWidget,	"focus-line-width",	&focusWidth,
								"focus-padding", 	&focusPad,
					 			"interior_focus",	&interiorFocus,
								"default_border",	&pBorder,
								(char *)NULL );

	// Make sure the border values exist, otherwise use some defaults
	if ( pBorder )
	{
		NW_gtk_border_set_from_border( aDefBorder, pBorder );
		gtk_border_free( pBorder );
	}
	else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );

	// If the button is too small, don't ever draw focus or grab more space
	if ( (w < 16) || (h < 16) )
		bDrawFocus = sal_False;

	NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );

    gint xi = x, yi = y, wi = w, hi = h;
	if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
	{
		xi += aDefBorder.left;
		yi += aDefBorder.top;
		wi -= aDefBorder.left + aDefBorder.right;
		hi -= aDefBorder.top + aDefBorder.bottom;
	}

	if ( !interiorFocus && bDrawFocus )
	{
		xi += focusWidth + focusPad;
		yi += focusWidth + focusPad;
		wi -= 2 * (focusWidth + focusPad);
		hi -= 2 * (focusWidth + focusPad);
	}

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        // Buttons must paint opaque since some themes have alpha-channel enabled buttons
        gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE, 
                            &clipRect, m_pWindow, "base", x, y, w, h );
        
        if ( (nState & CTRL_STATE_DEFAULT) && (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief == GTK_RELIEF_NORMAL) )
        {
            gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, 
                           &clipRect, gWidgetData[m_nScreen].gBtnWidget, "buttondefault", x, y, w, h );
        }
        
        if ( (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief != GTK_RELIEF_NONE)
            || (nState & CTRL_STATE_PRESSED)
		    || (nState & CTRL_STATE_ROLLOVER) )
        {
            gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, shadowType,
                           &clipRect, gWidgetData[m_nScreen].gBtnWidget, "button", xi, yi, wi, hi );
        }
    }
#if 0 // VCL draws focus rects
	// Draw focus rect
	if ( (nState & CTRL_STATE_FOCUSED) && (nState & CTRL_STATE_ENABLED) && bDrawFocus )
	{
		if (interiorFocus)
		{
			x += gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad;
			y += gWidgetData[m_nScreen].gBtnWidget->style->ythickness + focusPad;
			w -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
			h -=  2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
		}
		else
		{
			x -= focusWidth + focusPad;
			y -= focusWidth + focusPad;
			w += 2 * (focusWidth + focusPad);
			h += 2 * (focusWidth + focusPad);
		}
		if ( !interiorFocus )
			gtk_paint_focus( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, &clipRect,
                             gWidgetData[m_nScreen].gBtnWidget, "button", x, y, w, h );
	}
#endif

	return( sal_True );
}

static Rectangle NWGetButtonArea( int nScreen,
                                  ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
							      const ImplControlValue&, const OUString& )
{
	gboolean		interiorFocus;
	gint			focusWidth;
	gint			focusPad;
	GtkBorder		aDefBorder;
	GtkBorder *	pBorder;
	sal_Bool			bDrawFocus = sal_True;
	Rectangle		aRect;
	gint			x, y, w, h;

	NWEnsureGTKButton( nScreen );
	gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
                            	"focus-line-width",	&focusWidth,
								"focus-padding", 	&focusPad,
					 			"interior_focus",	&interiorFocus,
								"default_border",	&pBorder,
								(char *)NULL );

	// Make sure the border values exist, otherwise use some defaults
	if ( pBorder )
	{
		NW_gtk_border_set_from_border( aDefBorder, pBorder );
		gtk_border_free( pBorder );
	}
	else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );

	x = aAreaRect.Left();
	y = aAreaRect.Top();
	w = aAreaRect.GetWidth();
	h = aAreaRect.GetHeight();

	// If the button is too small, don't ever draw focus or grab more space
	if ( (w < 16) || (h < 16) )
		bDrawFocus = sal_False;

	if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
	{
		x -= aDefBorder.left;
		y -= aDefBorder.top;
		w += aDefBorder.left + aDefBorder.right;
		h += aDefBorder.top + aDefBorder.bottom;
	}

    aRect = Rectangle( Point( x, y ), Size( w, h ) );

	return( aRect );
}

//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
                                      ControlType, ControlPart,
                                      const Rectangle& rControlRectangle,
                                      const clipList& rClipList,
                                      ControlState nState, 
                                      const ImplControlValue& aValue,
                                      const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	sal_Bool			isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
    gint            x, y;
    GdkRectangle	clipRect;
   
	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKRadio( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

    gint indicator_size;
    gtk_widget_style_get( gWidgetData[m_nScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);

    x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
    y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
    
	// Set the shadow based on if checked or not so we get a freakin checkmark.
	shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
	NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidget, nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidgetSibling, nState, stateType );

	// GTK enforces radio groups, so that if we don't have 2 buttons in the group,
	// the single button will always be active.  So we have to have 2 buttons.
    
    // #i59666# set the members directly where we should use
    // gtk_toggle_button_set_active. reason: there are animated themes
    // which are in active state only after a while leading to painting
    // intermediate states between active/inactive. Let's hope that
    // GtkToggleButtone stays binary compatible.
	if (!isChecked)
		GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidgetSibling)->active = sal_True;
	GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidget)->active = isChecked;

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        gtk_paint_option( gWidgetData[m_nScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType, 
                          &clipRect, gWidgetData[m_nScreen].gRadioWidget, "radiobutton",
                          x, y, indicator_size, indicator_size );
    }
    
	return( sal_True );
}

//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
                                      ControlType, ControlPart,
                                      const Rectangle& rControlRectangle,
                                      const clipList& rClipList,
                                      ControlState nState, 
                                      const ImplControlValue& aValue,
                                      const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	bool			isChecked = (aValue.getTristateVal() == BUTTONVALUE_ON);
	bool            isInconsistent = (aValue.getTristateVal() == BUTTONVALUE_MIXED);
    GdkRectangle	clipRect;
    gint			x,y;

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKCheck( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

    gint indicator_size;
    gtk_widget_style_get( gWidgetData[m_nScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);

    x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
    y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
    
	// Set the shadow based on if checked or not so we get a checkmark.
	shadowType = isChecked ? GTK_SHADOW_IN : isInconsistent ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_OUT;
	NWSetWidgetState( gWidgetData[m_nScreen].gCheckWidget, nState, stateType );
	GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gCheckWidget)->active = isChecked;

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        gtk_paint_check( gWidgetData[m_nScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType, 
                         &clipRect, gWidgetData[m_nScreen].gCheckWidget, "checkbutton",
                         x, y, indicator_size, indicator_size );
    }

	return( sal_True );
}

//-------------------------------------
static void NWCalcArrowRect( const Rectangle& rButton, 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
        ) );
}

sal_Bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
                                          const Rectangle& rControlRectangle,
                                          const clipList&,
                                          ControlState nState, 
                                          const ImplControlValue& aValue,
                                          const OUString& )
{
    OSL_ASSERT( aValue.getType() == CTRL_SCROLLBAR );
    const ScrollbarValue* pScrollbarVal = (aValue.getType() == CTRL_SCROLLBAR) ? static_cast<const ScrollbarValue*>(&aValue) : NULL;
    GdkPixmap*      pixmap = NULL;
	Rectangle		pixmapRect, scrollbarRect;
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	GtkScrollbar *	scrollbarWidget;
	GtkStyle *	style;
	GtkAdjustment* scrollbarValues = NULL;
	GtkOrientation	scrollbarOrientation;
	Rectangle		thumbRect = pScrollbarVal->maThumbRect;
	Rectangle		button11BoundRect = pScrollbarVal->maButton1Rect;   // backward
	Rectangle		button22BoundRect = pScrollbarVal->maButton2Rect;   // forward
	Rectangle		button12BoundRect = pScrollbarVal->maButton1Rect;   // secondary forward
	Rectangle		button21BoundRect = pScrollbarVal->maButton2Rect;   // secondary backward
	GtkArrowType	button1Type;                                        // backward
	GtkArrowType	button2Type;                                        // forward
	gchar *		scrollbarTagH = (gchar *) "hscrollbar";
	gchar *		scrollbarTagV = (gchar *) "vscrollbar";
	gchar *		scrollbarTag = NULL;
	Rectangle		arrowRect;
	gint			slider_width = 0;
	gint			stepper_size = 0;
	gint			stepper_spacing = 0;
	gint			trough_border = 0;
	gint			min_slider_length = 0;
	gint			vShim = 0;
	gint			hShim = 0;
	gint			x,y,w,h;
    
    // 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() );

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKScrollbars( m_nScreen );
	NWEnsureGTKArrow( m_nScreen );
 
	// Find the overall bounding rect of the control
	pixmapRect = rControlRectangle;
    pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 1,
                              pixmapRect.GetHeight() + 1 ) );
	scrollbarRect = pixmapRect;

	if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
		return( sal_True );

	// Grab some button style attributes
	gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
                                      "slider_width", &slider_width,
									  "stepper_size", &stepper_size,
									  "trough_border", &trough_border,
									  "stepper_spacing", &stepper_spacing,
									  "min_slider_length", &min_slider_length, (char *)NULL );
    gboolean has_forward;
    gboolean has_forward2;
    gboolean has_backward;
    gboolean has_backward2;
    
	gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
									  "has-secondary-forward-stepper", &has_forward2,
									  "has-backward-stepper", &has_backward,
	   								  "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
	gint magic = trough_border ? 1 : 0;
    gint nFirst = 0;

    if ( has_backward )  nFirst  += 1;
    if ( has_forward2 )  nFirst  += 1;

	if ( nPart == PART_DRAW_BACKGROUND_HORZ )
	{
		unsigned int sliderHeight = slider_width + (trough_border * 2);
		vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;

		scrollbarRect.Move( 0, vShim );
		scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );

		scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollHorizWidget );
		scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
		scrollbarTag = scrollbarTagH;
		button1Type = GTK_ARROW_LEFT;
		button2Type = GTK_ARROW_RIGHT;

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

        button11BoundRect.Move( trough_border, (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+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
            button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
        }
        else
        {
            button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
        }

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

		thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
		// Make sure the thumb is at least the default width (so we don't get tiny thumbs),
		// but if the VCL gives us a size smaller than the theme's default thumb size,
		// honor the VCL size
#if 0
		if ( (thumbRect.GetWidth() < min_slider_length)
			&& ((scrollbarRect.GetWidth()-button1BoundRect.GetWidth()-button2BoundRect.GetWidth()) > min_slider_length) )
			thumbRect.SetSize( Size( min_slider_length, thumbRect.GetHeight() ) );
#endif

        thumbRect.Right() += magic;
		// Center vertically in the track
		thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
	}
	else
	{
		unsigned int sliderWidth = slider_width + (trough_border * 2);
		hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;

		scrollbarRect.Move( hShim, 0 );
		scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );

		scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollVertWidget );
		scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
		scrollbarTag = scrollbarTagV;
		button1Type = GTK_ARROW_UP;
		button2Type = GTK_ARROW_DOWN;

        if ( has_backward )
        {
            button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
                                    stepper_size + trough_border );
        }
        button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
        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+(trough_border+1)/2 );
            button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
        }
        else
        {
            button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
        }

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

		thumbRect.Right() = thumbRect.Left() + slider_width - 1;
#if 0
		// Make sure the thumb is at least the default width (so we don't get tiny thumbs),
		// but if the VCL gives us a size smaller than the theme's default thumb size,
		// honor the VCL size
		if ( (thumbRect.GetHeight() < min_slider_length)
			&& ((scrollbarRect.GetHeight()-button1BoundRect.GetHeight()-button2BoundRect.GetHeight()) > min_slider_length) )
			thumbRect.SetSize( Size( thumbRect.GetWidth(), min_slider_length ) );
#endif

        thumbRect.Bottom() += magic;
		// Center horizontally in the track
		thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
	}

    sal_Bool has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );

	scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
	if ( scrollbarValues == NULL )
		scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
	if ( nPart == PART_DRAW_BACKGROUND_HORZ )
	{
		scrollbarValues->lower = pScrollbarVal->mnMin;
		scrollbarValues->upper = pScrollbarVal->mnMax;
		scrollbarValues->value = pScrollbarVal->mnCur;
		scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
	}
	else
	{
		scrollbarValues->lower = pScrollbarVal->mnMin;
		scrollbarValues->upper = pScrollbarVal->mnMax;
		scrollbarValues->value = pScrollbarVal->mnCur;
		scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
	}
	gtk_adjustment_changed( scrollbarValues );
    
    // as multiple paints are required for the scrollbar
    // painting them directly to the window flickers
    pixmap = NWGetPixmapFromScreen( pixmapRect );
    if( ! pixmap )
        return sal_False;
    x = y = 0;
    
    w = pixmapRect.GetWidth();
    h = pixmapRect.GetHeight();    

    GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap );
    GdkRectangle* gdkRect = NULL; 

	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
	NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
	style = GTK_WIDGET( scrollbarWidget )->style;

	// ----------------- TROUGH
	gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, 
                        GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
                        m_pWindow, "base", x, y, 
                        w, h );
	gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, 
                   gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
                   x, y,
                   scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );

	if ( nState & CTRL_STATE_FOCUSED )
	{
		gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE, 
                         gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
                         x, y,
                         scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
	}

	// ----------------- THUMB
    if ( has_slider )
    {
	    NWConvertVCLStateToGTKState( pScrollbarVal->mnThumbState, &stateType, &shadowType );
	    if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )  stateType = GTK_STATE_PRELIGHT;
	    gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT, 
                        gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
                        x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(), 
                        thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
    }
	// ----------------- BUTTON 1 //
	if ( has_backward )
	{
        NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
        if ( stateType == GTK_STATE_INSENSITIVE )	stateType = GTK_STATE_NORMAL;
        gtk_paint_box( style, gdkDrawable, stateType, shadowType, 
                       gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
                       x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(), 
                       button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
        // ----------------- ARROW 1
    	NWCalcArrowRect( button11BoundRect, arrowRect );
    	gtk_paint_arrow( style, gdkDrawable, stateType, shadowType, 
                         gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
                         x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(), 
                         arrowRect.GetWidth(), arrowRect.GetHeight() );
    }
	if ( has_forward2 )
	{
        NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
        if ( stateType == GTK_STATE_INSENSITIVE )	stateType = GTK_STATE_NORMAL;
        gtk_paint_box( style, gdkDrawable, stateType, shadowType, 
                       gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
                       x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(), 
                       button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
        // ----------------- ARROW 1
    	NWCalcArrowRect( button12BoundRect, arrowRect );
    	gtk_paint_arrow( style, gdkDrawable, stateType, shadowType, 
                         gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
                         x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(), 
                         arrowRect.GetWidth(), arrowRect.GetHeight() );
    }
	// ----------------- BUTTON 2
    if ( has_backward2 )
    {
        NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
        if ( stateType == GTK_STATE_INSENSITIVE )	stateType = GTK_STATE_NORMAL;
        gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect, 
                       GTK_WIDGET(scrollbarWidget), "stepper",
                       x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(), 
                       button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
    	// ----------------- ARROW 2
    	NWCalcArrowRect( button21BoundRect, arrowRect );
        gtk_paint_arrow( style, gdkDrawable, stateType, shadowType, 
                         gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
                         x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(), 
                         arrowRect.GetWidth(), arrowRect.GetHeight() );
    }
    if ( has_forward )
    {
        NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
        if ( stateType == GTK_STATE_INSENSITIVE )	stateType = GTK_STATE_NORMAL;
        gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect, 
                       GTK_WIDGET(scrollbarWidget), "stepper",
                       x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(), 
                       button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
    	// ----------------- ARROW 2
    	NWCalcArrowRect( button22BoundRect, arrowRect );
        gtk_paint_arrow( style, gdkDrawable, stateType, shadowType, 
                         gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
                         x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(), 
                         arrowRect.GetWidth(), arrowRect.GetHeight() );
    }

    if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
    {
        g_object_unref( pixmap );
        return( sal_False );
    }
    g_object_unref( pixmap );
 
	return( sal_True );
}

//---

static Rectangle NWGetScrollButtonRect(	int nScreen, ControlPart nPart, Rectangle aAreaRect )
{
    gint slider_width;
    gint stepper_size;
    gint stepper_spacing;
    gint trough_border;

    NWEnsureGTKScrollbars( nScreen );

	// Grab some button style attributes
	gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
                                      "slider-width", &slider_width,
									  "stepper-size", &stepper_size,
									  "trough-border", &trough_border,
	   								  "stepper-spacing", &stepper_spacing, (char *)NULL );

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

	gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
                                      "has-forward-stepper", &has_forward,
									  "has-secondary-forward-stepper", &has_forward2,
									  "has-backward-stepper", &has_backward,
	   								  "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
	gint       buttonWidth;
	gint       buttonHeight;
	Rectangle  buttonRect;

    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;

    if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
    {
        buttonWidth = slider_width + 2 * trough_border;
        buttonHeight = stepper_size + trough_border + stepper_spacing;
    }
    else
    {
        buttonWidth = stepper_size + trough_border + stepper_spacing;
        buttonHeight = slider_width + 2 * trough_border;
    }
 
    if ( nPart == PART_BUTTON_UP )
    {
        buttonHeight *= nFirst;
        buttonHeight -= 1;
        buttonRect.setX( aAreaRect.Left() );
        buttonRect.setY( aAreaRect.Top() );
    }
    else if ( nPart == PART_BUTTON_LEFT )
    {
        buttonWidth *= nFirst;
        buttonWidth -= 1;
        buttonRect.setX( aAreaRect.Left() );
        buttonRect.setY( aAreaRect.Top() );
    }
    else if ( nPart == PART_BUTTON_DOWN )
    {
        buttonHeight *= nSecond;
        buttonRect.setX( aAreaRect.Left() );
        buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
    }
    else if ( nPart == PART_BUTTON_RIGHT )
    {
        buttonWidth *= nSecond;
        buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
        buttonRect.setY( aAreaRect.Top() );
    }

    buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );

	return( buttonRect );
}

//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
                                        ControlType nType, ControlPart nPart,
                                        const Rectangle& rControlRectangle,
                                        const clipList& rClipList,
                                        ControlState nState, 
                                        const ImplControlValue& aValue,
                                        const OUString& rCaption )
{
	Rectangle		pixmapRect;
    GdkRectangle    clipRect;
    
	// Find the overall bounding rect of the buttons's drawing area,
	// plus its actual draw rect excluding adornment
	pixmapRect = NWGetEditBoxPixmapRect( m_nScreen, nType, nPart, rControlRectangle,
					                     nState, aValue, rCaption );
    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
    }

	return( sal_True );
}


/* Take interior/exterior focus into account and return
 * the bounding rectangle of the edit box including
 * any focus requirements.
 */
static Rectangle NWGetEditBoxPixmapRect(int nScreen,
                                        ControlType,
								        ControlPart,
                                        Rectangle aAreaRect,
                                        ControlState,
                                        const ImplControlValue&,
                                        const OUString& )
{
	Rectangle		pixmapRect = aAreaRect;
	gboolean		interiorFocus;
	gint			focusWidth;

	NWEnsureGTKEditBox( nScreen );

	// Grab some entry style attributes
	gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
                                	"focus-line-width",	&focusWidth,
					 				"interior-focus",	&interiorFocus, (char *)NULL );

	if ( !interiorFocus )
	{
		pixmapRect.Move( -(focusWidth), -(focusWidth) );
        pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
                                  pixmapRect.GetHeight() + (2*(focusWidth)) ) );
	}

	return( pixmapRect );
}


/* Paint a GTK Entry widget into the specified GdkPixmap.
 * All coordinates should be local to the Pixmap, NOT
 * screen/window coordinates.
 */
static void NWPaintOneEditBox(	int nScreen,
                                GdkDrawable * gdkDrawable,
                                GdkRectangle *	gdkRect,
                                ControlType			nType,
                                ControlPart,
                                Rectangle				aEditBoxRect,
                                ControlState			nState,
                                const ImplControlValue&,
                                const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	GtkWidget      *widget;

	NWEnsureGTKButton( nScreen );
	NWEnsureGTKEditBox( nScreen );
	NWEnsureGTKSpinButton( nScreen );
	NWEnsureGTKCombo( nScreen );
	NWEnsureGTKScrolledWindow( nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

    /* border's shadowType for gtk entries is always GTK_SHADOW_IN (see gtkentry.c)
    shadowType = GTK_SHADOW_IN;
    */
    
	switch ( nType )
	{
		case CTRL_SPINBOX:
			widget = gWidgetData[nScreen].gSpinButtonWidget;
			break;

        case CTRL_MULTILINE_EDITBOX:
            widget = gWidgetData[nScreen].gScrolledWindowWidget;
            break;
		case CTRL_COMBOBOX:
			widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
			break;

		default:
			widget = gWidgetData[nScreen].gEditBoxWidget;
			break;
	}

	if ( stateType == GTK_STATE_PRELIGHT )
		stateType = GTK_STATE_NORMAL;

	// Blueprint needs to paint entry_bg with a Button widget, not an Entry widget to get
	// a nice white (or whatever default color) background
    GtkWidget* pBGWidget = widget;
    if( GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround )
    {
        NWSetWidgetState( gWidgetData[nScreen].gBtnWidget, nState, stateType );
        pBGWidget = gWidgetData[nScreen].gBtnWidget;
    }
	NWSetWidgetState( widget, nState, stateType );

	gtk_paint_flat_box( pBGWidget->style, gdkDrawable, stateType, GTK_SHADOW_NONE, 
                        gdkRect, pBGWidget, "entry_bg",
                        aEditBoxRect.Left(), aEditBoxRect.Top(), 
                        aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
	gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, 
                      gdkRect, widget, "entry",
                      aEditBoxRect.Left(), aEditBoxRect.Top(), 
                      aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );

}



//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
                                        const Rectangle& rControlRectangle,
                                        const clipList&,
                                        ControlState nState, 
                                        const ImplControlValue& aValue,
                                        const OUString& rCaption )
{
	GdkPixmap	*		pixmap;
	Rectangle			pixmapRect;
	GtkStateType		stateType;
	GtkShadowType		shadowType;
	const SpinbuttonValue *	pSpinVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue *>(&aValue) : NULL;
	Rectangle			upBtnRect;
	ControlPart		upBtnPart = PART_BUTTON_UP;
	ControlState		upBtnState = CTRL_STATE_ENABLED;
	Rectangle			downBtnRect;
	ControlPart		downBtnPart = PART_BUTTON_DOWN;
	ControlState		downBtnState = CTRL_STATE_ENABLED;

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKSpinButton( m_nScreen );
	NWEnsureGTKArrow( m_nScreen );

	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

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

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

	// CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
	if ( nType == CTRL_SPINBUTTONS )
	{
		if ( !pSpinVal )
		{
            std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
			return( false );
		}
		pixmapRect = pSpinVal->maUpperRect;
		pixmapRect.Union( pSpinVal->maLowerRect );
	}
	else
		pixmapRect = rControlRectangle;


	pixmap = NWGetPixmapFromScreen( pixmapRect );
	if ( !pixmap )
		return( sal_False );

	upBtnRect = NWGetSpinButtonRect( m_nScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
	downBtnRect = NWGetSpinButtonRect( m_nScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );

	if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
	{
		// Draw an edit field for SpinBoxes and ComboBoxes
		Rectangle aEditBoxRect( pixmapRect );
		aEditBoxRect.SetSize( Size( upBtnRect.Left() - pixmapRect.Left(), aEditBoxRect.GetHeight() ) );
		aEditBoxRect.setX( 0 );
		aEditBoxRect.setY( 0 );

		NWPaintOneEditBox( m_nScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
	}

	NWSetWidgetState( gWidgetData[m_nScreen].gSpinButtonWidget, nState, stateType );
	gtk_widget_style_get( gWidgetData[m_nScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );

	if ( shadowType != GTK_SHADOW_NONE )
	{
		Rectangle		shadowRect( upBtnRect );

		shadowRect.Union( downBtnRect );
		gtk_paint_box( gWidgetData[m_nScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL,
			gWidgetData[m_nScreen].gSpinButtonWidget, "spinbutton",
			(shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
			shadowRect.GetWidth(), shadowRect.GetHeight() );
	}

	NWPaintOneSpinButton( m_nScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
	NWPaintOneSpinButton( m_nScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );

	if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
	{
		g_object_unref( pixmap );
		return( sal_False );
	}

	g_object_unref( pixmap );
	return( sal_True );
}

//---

static Rectangle NWGetSpinButtonRect( int nScreen,
                                      ControlType,
								      ControlPart			nPart,
                                      Rectangle 			aAreaRect,
                                      ControlState,
                                      const ImplControlValue&,
                                      const OUString& )
{
	gint			buttonSize;
	Rectangle		buttonRect;

	NWEnsureGTKSpinButton( nScreen );

	buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
				   MIN_SPIN_ARROW_WIDTH );
	buttonSize -= buttonSize % 2 - 1; /* force odd */
	buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
                              buttonRect.GetHeight() ) );
	buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
	if ( nPart == PART_BUTTON_UP )
	{
		buttonRect.setY( aAreaRect.Top() );
		buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
	}
	else if( nPart == PART_BUTTON_DOWN )
	{
		buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
		buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
	}
    else
    {
        buttonRect.Right()  = buttonRect.Left()-1;
        buttonRect.Left()   = aAreaRect.Left();
        buttonRect.Top()    = aAreaRect.Top();
        buttonRect.Bottom() = aAreaRect.Bottom();
    }

	return( buttonRect );
}

//---

static void NWPaintOneSpinButton( int nScreen,
                                  GdkPixmap*			pixmap,
                                  ControlType			nType,
                                  ControlPart			nPart,
                                  Rectangle				aAreaRect,
                                  ControlState			nState,
                                  const ImplControlValue&	aValue,
                                  const OUString&				rCaption )
{
	Rectangle			buttonRect;
	GtkStateType		stateType;
	GtkShadowType		shadowType;
	Rectangle			arrowRect;
	gint				arrowSize;

	NWEnsureGTKSpinButton( nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

	buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );

	NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
	gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
			(nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
			(buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
			buttonRect.GetWidth(), buttonRect.GetHeight() );

	arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
	arrowSize -= arrowSize % 2 - 1; /* force odd */
    arrowRect.SetSize( Size( arrowSize, arrowSize ) );
	arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
	if ( nPart == PART_BUTTON_UP )
		arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
	else
		arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);

	gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
			"spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, sal_True,
			(arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
			arrowRect.GetWidth(), arrowRect.GetHeight() );
}


//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
                                         ControlType nType, ControlPart nPart,
                                         const Rectangle& rControlRectangle,
                                         const clipList& rClipList,
                                         ControlState nState, 
                                         const ImplControlValue& aValue,
                                         const OUString& rCaption )
{
	Rectangle		pixmapRect;
	Rectangle		buttonRect;
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	Rectangle		arrowRect;
    gint			x,y;
    GdkRectangle	clipRect;

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKArrow( m_nScreen );
	NWEnsureGTKCombo( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

	// Find the overall bounding rect of the buttons's drawing area,
	// plus its actual draw rect excluding adornment
	pixmapRect = rControlRectangle;
    x = rControlRectangle.Left();
    y = rControlRectangle.Top();

	NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gComboWidget, nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gArrowWidget, nState, stateType );

    buttonRect = NWGetComboBoxButtonRect( m_nScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
    if( nPart == PART_BUTTON_DOWN )
        buttonRect.Left() += 1;

	Rectangle		aEditBoxRect( pixmapRect );
	aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );

    #define ARROW_EXTENT		0.7
	arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
	                         (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
	arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
                             buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        if( nPart == PART_ENTIRE_CONTROL )
            NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect, 
                               nState, aValue, rCaption );
        
        // Buttons must paint opaque since some themes have alpha-channel enabled buttons
        gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE, 
                            &clipRect, m_pWindow, "base", 
                            x+(buttonRect.Left() - pixmapRect.Left()), 
                            y+(buttonRect.Top() - pixmapRect.Top()),
                            buttonRect.GetWidth(), buttonRect.GetHeight() );
        gtk_paint_box( GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
                       &clipRect, GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button, "button",
                       x+(buttonRect.Left() - pixmapRect.Left()), 
                       y+(buttonRect.Top() - pixmapRect.Top()),
                       buttonRect.GetWidth(), buttonRect.GetHeight() );

        gtk_paint_arrow( gWidgetData[m_nScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
                         &clipRect, gWidgetData[m_nScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, sal_True,
                         x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
                         arrowRect.GetWidth(), arrowRect.GetHeight() );
    }
    
	return( sal_True );
}

//----

static Rectangle NWGetComboBoxButtonRect( int nScreen,
                                          ControlType,
									      ControlPart nPart,
                                          Rectangle				aAreaRect,
                                          ControlState,
                                          const ImplControlValue&,
                                          const OUString& )
{
	Rectangle	aButtonRect;
	gint		nArrowWidth;
    gint        nButtonWidth;
	gint		nFocusWidth;
	gint		nFocusPad;

	NWEnsureGTKArrow( nScreen );

	// Grab some button style attributes
	gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
                                  	"focus-line-width",	&nFocusWidth,
									"focus-padding", 	&nFocusPad, (char *)NULL );

	nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
    nButtonWidth = nArrowWidth +
                   ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
				   + (2 * (nFocusWidth+nFocusPad));
    if( nPart == PART_BUTTON_DOWN )
    {
        aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
        aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
                                   aAreaRect.Top() ) );
    }
    else if( nPart == PART_SUB_EDIT )
    {
        NWEnsureGTKCombo( nScreen );
        
        gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
                        nFocusWidth +
                        nFocusPad;
        gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
        adjust_x     += gWidgetData[nScreen].gComboWidget->style->xthickness;
        aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
                                   aAreaRect.GetHeight() - 2 * adjust_y ) );
        Point aEditPos = aAreaRect.TopLeft();
        aEditPos.X() += adjust_x;
        aEditPos.Y() += adjust_y;
        aButtonRect.SetPos( aEditPos );
    }

	return( aButtonRect );
}

//-------------------------------------


    
sal_Bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
                                        const Rectangle& rControlRectangle,
                                        const clipList&,
                                        ControlState nState, 
                                        const ImplControlValue& aValue,
                                        const OUString& )
{
    OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM );
	GdkPixmap *	pixmap;
	Rectangle		pixmapRect;
	Rectangle		tabRect;
	GtkStateType	stateType;
	GtkShadowType	shadowType;
    if( ! gWidgetData[ m_nScreen ].gCacheTabItems )
    {
        gWidgetData[ m_nScreen ].gCacheTabItems = new NWPixmapCache( m_nScreen );
        gWidgetData[ m_nScreen ].gCacheTabPages = new NWPixmapCache( m_nScreen );
    }
    NWPixmapCache& aCacheItems = *gWidgetData[ m_nScreen ].gCacheTabItems;
    NWPixmapCache& aCachePage = *gWidgetData[ m_nScreen ].gCacheTabPages;

    if( !aCacheItems.GetSize() )
        aCacheItems.SetSize( 20 );
    if( !aCachePage.GetSize() )
        aCachePage.SetSize( 1 );
    
	if ( (nType == CTRL_TAB_ITEM) && (aValue.getType() != CTRL_TAB_ITEM) )
	{
		return( false );
	}

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKNotebook( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

	// Find the overall bounding rect of the buttons's drawing area,
	// plus its actual draw rect excluding adornment
	pixmapRect = rControlRectangle;
	if ( nType == CTRL_TAB_ITEM )
	{
        const TabitemValue *	pTabitemValue = static_cast<const TabitemValue *>(&aValue);
		if ( !pTabitemValue->isFirst() )
		{
			// GTK+ tabs overlap on the right edge (the top tab obscures the
			// left edge of the tab right "below" it, so adjust the rectangle
			// to draw tabs slightly large so the overlap happens
			pixmapRect.Move( -2, 0 );
			pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
		}
		if ( nState & CTRL_STATE_SELECTED )
		{
			// In GTK+, the selected tab is 2px taller than all other tabs
			pixmapRect.Move( 0, -2 );
			pixmapRect.Bottom() += 2;
			tabRect = pixmapRect;
			// Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
			tabRect.Bottom() -= 1;
		}
		else
			tabRect = pixmapRect;

		// Allow the tab to draw a right border if needed
		tabRect.Right() -= 1;
    
        // #129732# avoid degenerate cases which might lead to crashes
        if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
            return false;
	}

    if( nType == CTRL_TAB_ITEM )
    {
        if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap ) )
            return NWRenderPixmapToScreen( pixmap, pixmapRect );
    }
    else
    {
        if( aCachePage.Find( nType, nState, pixmapRect, &pixmap ) )
            return NWRenderPixmapToScreen( pixmap, pixmapRect );
    }

        
//	gtk_widget_set_state( gWidgetData[m_nScreen].gNotebookWidget, stateType );

    pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(), 
                             GetX11SalData()->GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
    GdkRectangle paintRect;
    paintRect.x = paintRect.y = 0;
    paintRect.width = pixmapRect.GetWidth();
    paintRect.height = pixmapRect.GetHeight();
                             
    gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL, 
		                GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", 0, 0, -1, -1);

	NWSetWidgetState( gWidgetData[m_nScreen].gNotebookWidget, nState, stateType );
    
	switch( nType )
	{
		case CTRL_TAB_BODY:
			break;

		case CTRL_FIXEDBORDER:
		case CTRL_TAB_PANE:
			gtk_paint_box_gap( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
				(char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
			break;

		case CTRL_TAB_ITEM:
			stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;

			gtk_paint_extension( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
				(char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
				tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );

			if ( nState & CTRL_STATE_SELECTED )
			{
				gtk_paint_flat_box( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
					(char *)"base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
			}
			break;

		default:
			break;
	}

	// Crux seems to think it can make the pane without a left edge
	if ( nType == CTRL_FIXEDBORDER )
		pixmapRect.Move( 1, 0 );

    // cache data
    if( nType == CTRL_TAB_ITEM )
        aCacheItems.Fill( nType, nState, pixmapRect, pixmap );
    else
        aCachePage.Fill( nType, nState, pixmapRect, pixmap );
        
	sal_Bool bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect);
	g_object_unref( pixmap );
	return bSuccess;
}

//-------------------------------------

sal_Bool GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
                                        ControlType nType, ControlPart nPart,
                                        const Rectangle& rControlRectangle,
                                        const clipList& rClipList,
                                        ControlState nState, 
                                        const ImplControlValue& aValue,
                                        const OUString& rCaption )
{
	Rectangle		pixmapRect;
	Rectangle		widgetRect;
	Rectangle		aIndicatorRect;
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	gint			bInteriorFocus;
	gint			nFocusLineWidth;
	gint			nFocusPadding;
    gint			x,y;
    GdkRectangle    clipRect;

	NWEnsureGTKButton( m_nScreen );
	NWEnsureGTKOptionMenu( m_nScreen );
	NWEnsureGTKScrolledWindow( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

	// Find the overall bounding rect of the buttons's drawing area,
	// plus its actual draw rect excluding adornment
	pixmapRect = rControlRectangle;
	if ( nPart == PART_WINDOW )
	{
		// Make the widget a _bit_ bigger
		pixmapRect.SetPos( Point( pixmapRect.Left() - 1,
                                  pixmapRect.Top() - 1 ) );
		pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2,
		                          pixmapRect.GetHeight() + 2 ) );
	}

	widgetRect = pixmapRect;
    x = pixmapRect.Left();
    y = pixmapRect.Top();

    // set up references to correct drawable and cliprect
	NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gOptionMenuWidget, nState, stateType );
	NWSetWidgetState( gWidgetData[m_nScreen].gScrolledWindowWidget, nState, stateType );

	if ( nPart != PART_WINDOW )
	{
		gtk_widget_style_get( gWidgetData[m_nScreen].gOptionMenuWidget,
			"interior_focus",	&bInteriorFocus,
			"focus_line_width",	&nFocusLineWidth,
			"focus_padding",	&nFocusPadding,
			(char *)NULL);
    }
    
    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
    
        if ( nPart != PART_WINDOW )
        {
            // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
            gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE, 
                                &clipRect, m_pWindow, "base", x, y, 
                                pixmapRect.GetWidth(), pixmapRect.GetHeight() );
            gtk_paint_box( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
                           gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenu",
                           x+(widgetRect.Left() - pixmapRect.Left()), 
                           y+(widgetRect.Top() - pixmapRect.Top()),
                           widgetRect.GetWidth(), widgetRect.GetHeight() );
            aIndicatorRect = NWGetListBoxIndicatorRect( m_nScreen, nType, nPart, widgetRect, nState, 
                                                        aValue, rCaption );
            gtk_paint_tab( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
                           gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenutab",
                           x+(aIndicatorRect.Left() - pixmapRect.Left()), 
                           y+(aIndicatorRect.Top() - pixmapRect.Top()),
                           aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
        }
        else
        {
            shadowType = GTK_SHADOW_IN;
        
            gtk_paint_shadow( gWidgetData[m_nScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
                &clipRect, gWidgetData[m_nScreen].gScrolledWindowWidget, "scrolled_window",
                x+(widgetRect.Left() - pixmapRect.Left()), y+(widgetRect.Top() - pixmapRect.Top()),
                widgetRect.GetWidth(), widgetRect.GetHeight() );
        }
    }
    
	return( sal_True );
}

sal_Bool GtkSalGraphics::NWPaintGTKToolbar(
            GdkDrawable* gdkDrawable,
            ControlType, ControlPart nPart,
			const Rectangle& rControlRectangle,
            const clipList& rClipList,
            ControlState nState, const ImplControlValue& aValue,
			const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
	gint			x, y, w, h;
    gint            g_x=0, g_y=0, g_w=10, g_h=10;
    bool            bPaintButton = true;
    GtkWidget*      pButtonWidget = gWidgetData[m_nScreen].gToolbarButtonWidget;
    GdkRectangle	clipRect;
    
	NWEnsureGTKToolbar( m_nScreen );
    if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
        nState &= ~CTRL_STATE_FOCUSED;
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
    
	x = rControlRectangle.Left();
    y = rControlRectangle.Top();
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    // handle toolbar
    if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
    {
	    NWSetWidgetState( gWidgetData[m_nScreen].gToolbarWidget, nState, stateType );

        GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
        if ( nState & CTRL_STATE_ENABLED )
            GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );

        if( nPart == PART_DRAW_BACKGROUND_HORZ )
            gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
        else
            gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
    }        
    // handle grip
    else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
    {
	    NWSetWidgetState( gWidgetData[m_nScreen].gHandleBoxWidget, nState, stateType );

        GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
        if ( nState & CTRL_STATE_ENABLED )
            GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );

        gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nScreen].gHandleBoxWidget), shadowType );

        // evaluate grip rect
        if( aValue.getType() == CTRL_TOOLBAR )
        {
            const ToolbarValue* pVal = static_cast<const ToolbarValue*>(&aValue);
            g_x = pVal->maGripRect.Left();
            g_y = pVal->maGripRect.Top();
            g_w = pVal->maGripRect.GetWidth();
            g_h = pVal->maGripRect.GetHeight();
        }
    }
    // handle button
    else if( nPart == PART_BUTTON )
    {
        bPaintButton =
            (GTK_BUTTON(pButtonWidget)->relief != GTK_RELIEF_NONE)
            || (nState & CTRL_STATE_PRESSED)
		    || (nState & CTRL_STATE_ROLLOVER); 
        if( aValue.getTristateVal() == BUTTONVALUE_ON )
        {
            pButtonWidget = gWidgetData[m_nScreen].gToolbarToggleWidget;
            shadowType = GTK_SHADOW_IN;
            stateType = GTK_STATE_ACTIVE;
            // special case stateType value for depressed toggle buttons
            // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state)
            if( (nState & (CTRL_STATE_ROLLOVER|CTRL_STATE_PRESSED)) )
            {
                stateType = GTK_STATE_PRELIGHT;
                shadowType = GTK_SHADOW_OUT;
            }
            bPaintButton = true;
        }
        else
            stateType = GTK_STATE_PRELIGHT; // only for bPaintButton = true, in which case always rollver is meant
        
        NWSetWidgetState( pButtonWidget, nState, stateType );
        gtk_widget_ensure_style( pButtonWidget );            
    }        
    
    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        // draw toolbar
        if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
        {
            gtk_paint_flat_box( gWidgetData[m_nScreen].gToolbarWidget->style,
                                gdkDrawable,
                                (GtkStateType)GTK_STATE_NORMAL,
                                GTK_SHADOW_NONE, 
                                &clipRect,
                                gWidgetData[m_nScreen].gToolbarWidget,
                                "base",
                                x, y, w, h );
            gtk_paint_box( gWidgetData[m_nScreen].gToolbarWidget->style,
                           gdkDrawable,
                           stateType,
                           shadowType,
                           &clipRect,
                           gWidgetData[m_nScreen].gToolbarWidget,
                           "toolbar",
                           x, y, w, h );
        }
        // draw grip
        else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
        {
            gtk_paint_handle( gWidgetData[m_nScreen].gHandleBoxWidget->style,
                              gdkDrawable,
                              GTK_STATE_NORMAL,
                              GTK_SHADOW_OUT,
                              &clipRect,
                              gWidgetData[m_nScreen].gHandleBoxWidget,
                              "handlebox",
                              g_x, g_y, g_w, g_h,
                              nPart == PART_THUMB_HORZ ?
                              GTK_ORIENTATION_HORIZONTAL :
                              GTK_ORIENTATION_VERTICAL
                              );
        }
        // draw button
        else if( nPart == PART_BUTTON )
        {
            if( bPaintButton )
            {
                gtk_paint_box( pButtonWidget->style, gdkDrawable,
                               stateType,
                               shadowType,
                               &clipRect,
                               pButtonWidget, "button", x, y, w, h );
            }        
        }
    }
    
	return( sal_True );
}

//----

sal_Bool GtkSalGraphics::NWPaintGTKMenubar(
            GdkDrawable* gdkDrawable,
            ControlType, ControlPart nPart,
			const Rectangle& rControlRectangle,
            const clipList& rClipList,
            ControlState nState, const ImplControlValue&,
			const OUString& )
{
	GtkStateType	stateType;
	GtkShadowType	shadowType;
    GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
	gint			x, y, w, h;
    GdkRectangle	clipRect;
    
	NWEnsureGTKMenubar( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
    
	x = rControlRectangle.Left();
    y = rControlRectangle.Top();
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    if( nPart == PART_MENU_ITEM )
    {
        if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
        {
            gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenubarWidget,
                                  "selected_shadow_type", &selected_shadow_type,
                                  (char *)NULL);
        }
    }
    
    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        // handle Menubar
        if( nPart == PART_ENTIRE_CONTROL )
        {
            NWSetWidgetState( gWidgetData[m_nScreen].gMenubarWidget, nState, stateType );
            
            GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
            if ( nState & CTRL_STATE_ENABLED )
                GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );

            // #118704# for translucent menubar styles paint background first
            gtk_paint_flat_box( gWidgetData[m_nScreen].gMenubarWidget->style,
                                gdkDrawable,
                                GTK_STATE_NORMAL,
                                GTK_SHADOW_NONE, 
                                &clipRect,
                                GTK_WIDGET(m_pWindow),
                                "base", 
                                x, y, w, h );
            gtk_paint_box( gWidgetData[m_nScreen].gMenubarWidget->style,
                           gdkDrawable,
                           stateType,
                           shadowType,
                           &clipRect,
                           gWidgetData[m_nScreen].gMenubarWidget,
                           "menubar",
                           x, y, w, h );
        }
        else if( nPart == PART_MENU_ITEM )
        {
            if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
            {
                gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenubarWidget->style,
                               gdkDrawable,
                               GTK_STATE_PRELIGHT,
                               selected_shadow_type,
                               &clipRect,
                               gWidgetData[m_nScreen].gMenuItemMenubarWidget,
                               "menuitem",
                               x, y, w, h);
            }
        }
    }
    
	return( sal_True );
}

sal_Bool GtkSalGraphics::NWPaintGTKPopupMenu(
            GdkDrawable* gdkDrawable,
            ControlType, ControlPart nPart,
			const Rectangle& rControlRectangle,
            const clipList& rClipList,
            ControlState nState, const ImplControlValue&,
			const OUString& )
{
    // #i50745# gtk does not draw disabled menu entries (and crux theme
    // even crashes), draw them using vcl functionality.
    if( nPart == PART_MENU_ITEM && ! (nState & CTRL_STATE_ENABLED) )
        return sal_False;
    
	GtkStateType	stateType;
	GtkShadowType	shadowType;
    GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
	gint			x, y, w, h;
    GdkRectangle	clipRect;
    
	NWEnsureGTKMenu( m_nScreen );
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
    
	x = rControlRectangle.Left();
    y = rControlRectangle.Top();
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    if( nPart == PART_MENU_ITEM &&
        ( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) ) )
    {
        gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenuWidget,
                              "selected_shadow_type", &selected_shadow_type,
                              (char *)NULL);
    }

    NWSetWidgetState( gWidgetData[m_nScreen].gMenuWidget, nState, stateType );

    GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
    if ( nState & CTRL_STATE_ENABLED )
        GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        if( nPart == PART_ENTIRE_CONTROL )
        {
            // #118704# for translucent menubar styles paint background first
            gtk_paint_flat_box( gWidgetData[m_nScreen].gMenuWidget->style,
                                gdkDrawable,
                                GTK_STATE_NORMAL,
                                GTK_SHADOW_NONE, 
                                &clipRect,
                                GTK_WIDGET(m_pWindow),
                                "base", 
                                x, y, w, h );
            gtk_paint_box( gWidgetData[m_nScreen].gMenuWidget->style,
                           gdkDrawable,
                           GTK_STATE_NORMAL,
                           GTK_SHADOW_OUT,
                           &clipRect,
                           gWidgetData[m_nScreen].gMenuWidget,
                           "menu",
                           x, y, w, h );
        }
        else if( nPart == PART_MENU_ITEM )
        {
            if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
            {
                if( nState & CTRL_STATE_ENABLED )
                gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
                               gdkDrawable,
                               GTK_STATE_PRELIGHT,
                               selected_shadow_type,
                               &clipRect,
                               gWidgetData[m_nScreen].gMenuItemMenuWidget,
                               "menuitem",
                               x, y, w, h);
            }
        }
        else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
        {
            GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
                                 gWidgetData[m_nScreen].gMenuItemCheckMenuWidget :
                                 gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;

            GtkStateType nStateType = GTK_STATE_NORMAL;
            GtkShadowType nShadowType;

            if ( nState & CTRL_STATE_SELECTED )
                nStateType = GTK_STATE_PRELIGHT;

            NWSetWidgetState( pWidget, nState, nStateType );

            if ( nState & CTRL_STATE_PRESSED )
                nShadowType = GTK_SHADOW_IN;
            else
                nShadowType = GTK_SHADOW_OUT;

            if ( nPart == PART_MENU_ITEM_CHECK_MARK )
            {
                gtk_paint_check( pWidget->style,
                                 gdkDrawable,
                                 nStateType,
                                 nShadowType,
                                 &clipRect,
                                 gWidgetData[m_nScreen].gMenuItemMenuWidget,
                                 "check",
                                 x, y, w, h );
            }
            else
            {
                gtk_paint_option( pWidget->style,
                                  gdkDrawable,
                                  nStateType,
                                  nShadowType,
                                  &clipRect,
                                  gWidgetData[m_nScreen].gMenuItemMenuWidget,
                                  "option",
                                  x, y, w, h );
            }
        }
    }
    
	return( sal_True );
}

sal_Bool GtkSalGraphics::NWPaintGTKTooltip(
            GdkDrawable* gdkDrawable,
            ControlType, ControlPart,
			const Rectangle& rControlRectangle,
            const clipList& rClipList,
            ControlState, const ImplControlValue&,
			const OUString& )
{
    NWEnsureGTKTooltip( m_nScreen );
    
	gint			x, y, w, h;
    GdkRectangle	clipRect;
    
	x = rControlRectangle.Left();
    y = rControlRectangle.Top();
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
    {
        clipRect.x = it->Left();
        clipRect.y = it->Top();
        clipRect.width = it->GetWidth();
        clipRect.height = it->GetHeight();
        
        gtk_paint_flat_box( gWidgetData[m_nScreen].gTooltipPopup->style,
                            gdkDrawable,
                            GTK_STATE_NORMAL,
                            GTK_SHADOW_OUT,
                            &clipRect,
                            gWidgetData[m_nScreen].gTooltipPopup,
                            "tooltip", 
                            x, y, w, h );
    }
    
	return( sal_True );
}

sal_Bool GtkSalGraphics::NWPaintGTKListNode(
            GdkDrawable*,
            ControlType, ControlPart,
			const Rectangle& rControlRectangle,
            const clipList&,
            ControlState nState, const ImplControlValue& rValue,
			const OUString& )
{
    NWEnsureGTKTreeView( m_nScreen );

    Rectangle aRect( rControlRectangle );
    aRect.Left() -= 2;
    aRect.Right() += 2;
    aRect.Top() -= 2;
    aRect.Bottom() += 2;
	gint			w, h;
	w = aRect.GetWidth();
	h = aRect.GetHeight();

	GtkStateType	stateType;
	GtkShadowType	shadowType;
	NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );

    ButtonValue aButtonValue = rValue.getTristateVal();
    GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;

    switch( aButtonValue )
    {
        case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
        case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
        default:
            break;
    }
    
    GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect );
    if( ! pixmap )
        return sal_False;
    
    GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
    gtk_paint_expander( gWidgetData[m_nScreen].gTreeView->style,
                        pixDrawable,
                        stateType,
                        NULL,
                        gWidgetData[m_nScreen].gTreeView,
                        "treeview",
                        w/2, h/2,
                        eStyle );

	sal_Bool bRet = NWRenderPixmapToScreen( pixmap, aRect );
    g_object_unref( pixmap );

	return bRet;
}

sal_Bool GtkSalGraphics::NWPaintGTKProgress(
            GdkDrawable*,
            ControlType, ControlPart,
			const Rectangle& rControlRectangle,
            const clipList&,
            ControlState, const ImplControlValue& rValue,
			const OUString& )
{
    NWEnsureGTKProgressBar( m_nScreen );
    
	gint			w, h;
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    long nProgressWidth = rValue.getNumericVal();
    
    GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) );
    if( ! pixmap )
        return sal_False;
    
    GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );

    // paint background
    gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
                        pixDrawable,
                        GTK_STATE_NORMAL,
                        GTK_SHADOW_NONE,
                        NULL,
                        gWidgetData[m_nScreen].gProgressBar,
                        "trough", 
                        0, 0, w, h );
    if( nProgressWidth > 0 )
    {
        // paint progress
        if( Application::GetSettings().GetLayoutRTL() )
        {
            gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
                           pixDrawable,
                           GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
                           NULL,
                           gWidgetData[m_nScreen].gProgressBar,
                           "bar",
                           w-nProgressWidth, 0, nProgressWidth, h
                           );
        }
        else
        {
            gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
                           pixDrawable,
                           GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
                           NULL,
                           gWidgetData[m_nScreen].gProgressBar,
                           "bar",
                           0, 0, nProgressWidth, h
                           );
        }
    }

	sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
    g_object_unref( pixmap );

	return bRet;
}

sal_Bool GtkSalGraphics::NWPaintGTKSlider(
            GdkDrawable*,
            ControlType, ControlPart nPart,
			const Rectangle& rControlRectangle,
            const clipList&,
            ControlState nState, const ImplControlValue& rValue,
			const OUString& )
{
    OSL_ASSERT( rValue.getType() == CTRL_SLIDER );
    NWEnsureGTKSlider( m_nScreen );
    
	gint			w, h;
	w = rControlRectangle.GetWidth();
	h = rControlRectangle.GetHeight();

    const SliderValue* pVal = static_cast<const SliderValue*>(&rValue);
    
    GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle );
    if( ! pixmap )
        return sal_False;
    
    GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
    GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
                         ? GTK_WIDGET(gWidgetData[m_nScreen].gHScale)
                         : GTK_WIDGET(gWidgetData[m_nScreen].gVScale);
    const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
    GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
    GtkStateType eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE;
    gint slider_width = 10;
    gint slider_length = 10;
    gint trough_border = 0;
    gtk_widget_style_get( pWidget,
                          "slider-width", &slider_width,
                          "slider-length", &slider_length,
                          "trough-border", &trough_border,
                          NULL);

    eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
    if( nPart == PART_TRACK_HORZ_AREA )
    {
        gtk_paint_box( pWidget->style,
                       pixDrawable,
                       eState,
                       GTK_SHADOW_IN,
                       NULL,
                       pWidget,
                       "trough",
                       0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
        gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
        gtk_paint_slider( pWidget->style,
                          pixDrawable,
                          eState,
                          GTK_SHADOW_OUT,
                          NULL,
                          pWidget,
                          pDetail,
                          x, (h-slider_width)/2,
                          slider_length, slider_width,
                          eOri );
    }
    else
    {
        gtk_paint_box( pWidget->style,
                       pixDrawable,
                       eState,
                       GTK_SHADOW_IN,
                       NULL,
                       pWidget,
                       "trough",
                       (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
        gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
        gtk_paint_slider( pWidget->style,
                          pixDrawable,
                          eState,
                          GTK_SHADOW_OUT,
                          NULL,
                          pWidget,
                          pDetail,
                          (w-slider_width)/2, y,
                          slider_width, slider_length,
                          eOri );
    }
    #if 0
    // paint background
    gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
                        pixDrawable,
                        GTK_STATE_NORMAL,
                        GTK_SHADOW_NONE,
                        NULL,
                        gWidgetData[m_nScreen].gProgressBar,
                        "trough", 
                        0, 0, w, h );
    if( nProgressWidth > 0 )
    {
        // paint progress
        if( Application::GetSettings().GetLayoutRTL() )
        {
            gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
                           pixDrawable,
                           GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
                           NULL,
                           gWidgetData[m_nScreen].gProgressBar,
                           "bar",
                           w-nProgressWidth, 0, nProgressWidth, h
                           );
        }
        else
        {
            gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
                           pixDrawable,
                           GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
                           NULL,
                           gWidgetData[m_nScreen].gProgressBar,
                           "bar",
                           0, 0, nProgressWidth, h
                           );
        }
    }
    #endif

	sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
    g_object_unref( pixmap );

	return bRet;
}

//----

static Rectangle NWGetListBoxButtonRect( int nScreen,
                                         ControlType,
                                         ControlPart    nPart,
                                         Rectangle      aAreaRect,
                                         ControlState,
                                         const ImplControlValue&,
                                         const OUString& )
{
	Rectangle       aPartRect;
	GtkRequisition *pIndicatorSize = NULL;
	GtkBorder      *pIndicatorSpacing = NULL;
	gint            width = 13;	// GTK+ default
	gint            right = 5;	// GTK+ default
	gint            nButtonAreaWidth = 0;
    gint            xthickness = 0;

	NWEnsureGTKOptionMenu( nScreen );

	gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
			"indicator_size",	&pIndicatorSize,
			"indicator_spacing",&pIndicatorSpacing, (char *)NULL);
	
	if ( pIndicatorSize )
		width = pIndicatorSize->width;

	if ( pIndicatorSpacing )
		right = pIndicatorSpacing->right;

    Size aPartSize( 0, aAreaRect.GetHeight() );
    Point aPartPos ( 0, aAreaRect.Top() );

    xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
	nButtonAreaWidth = width + right + (xthickness * 2);
	switch( nPart )
	{
		case PART_BUTTON_DOWN:
			aPartSize.Width() = nButtonAreaWidth;
			aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
			break;

		case PART_SUB_EDIT:
			aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
			aPartPos.X() = aAreaRect.Left() + xthickness;
			break;

		default:
			aPartSize.Width() = aAreaRect.GetWidth();	
			aPartPos.X() = aAreaRect.Left();
			break;
	}
    aPartRect = Rectangle( aPartPos, aPartSize );

	if ( pIndicatorSize )
		gtk_requisition_free( pIndicatorSize );
	if ( pIndicatorSpacing )
		gtk_border_free( pIndicatorSpacing );

	return( aPartRect );
}

//----

static Rectangle NWGetListBoxIndicatorRect( int nScreen,
                                            ControlType,
                                            ControlPart,
                                            Rectangle				aAreaRect,
                                            ControlState,
                                            const ImplControlValue&,
                                            const OUString& )
{
	Rectangle       aIndicatorRect;
	GtkRequisition *pIndicatorSize = NULL;
	GtkBorder      *pIndicatorSpacing = NULL;
	gint            width = 13;	// GTK+ default
	gint            height = 13;	// GTK+ default
	gint            right = 5;	// GTK+ default

	NWEnsureGTKOptionMenu( nScreen );

	gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
			"indicator_size",	&pIndicatorSize,
			"indicator_spacing",&pIndicatorSpacing, (char *)NULL);
	
	if ( pIndicatorSize )
    {
		width = pIndicatorSize->width;
		height = pIndicatorSize->height;
    }

	if ( pIndicatorSpacing )
		right = pIndicatorSpacing->right;

    aIndicatorRect.SetSize( Size( width, height ) );
	aIndicatorRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness,
                                  aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );

	// If height is odd, move the indicator down 1 pixel
	if ( aIndicatorRect.GetHeight() % 2 )
		aIndicatorRect.Move( 0, 1 );

	if ( pIndicatorSize )
		gtk_requisition_free( pIndicatorSize );
	if ( pIndicatorSpacing )
		gtk_border_free( pIndicatorSpacing );

	return( aIndicatorRect );
}

static Rectangle NWGetToolbarRect(  int nScreen,
                                    ControlType,
									ControlPart				nPart,
									Rectangle				aAreaRect,
									ControlState,
									const ImplControlValue&,
									const OUString& )
{
    Rectangle aRet;

    if( nPart == PART_DRAW_BACKGROUND_HORZ ||
        nPart == PART_DRAW_BACKGROUND_VERT )
        aRet = aAreaRect;
    else if( nPart == PART_THUMB_HORZ )
        aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
    else if( nPart == PART_THUMB_VERT )
        aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
    else if( nPart == PART_BUTTON )
    {
        aRet = aAreaRect;
        
        NWEnsureGTKToolbar( nScreen );
        
        gint nMinWidth =
            2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
            + 1 // CHILD_SPACING constant, found in gtk_button.c
            + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
        gint nMinHeight =
            2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
            + 1 // CHILD_SPACING constant, found in gtk_button.c
            + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor                          
        
        gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
        if( aAreaRect.GetWidth() < nMinWidth )
            aRet.Right() = aRet.Left() + nMinWidth;
        if( aAreaRect.GetHeight() < nMinHeight  )
            aRet.Bottom() = aRet.Top() + nMinHeight;
    }

    return aRet;
}

/************************************************************************
 * helper for GtkSalFrame
 ************************************************************************/
static inline Color getColor( const GdkColor& rCol )
{
    return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
}

#if OSL_DEBUG_LEVEL > 1

void printColor( const char* name, const GdkColor& rCol )
{
    std::fprintf( stderr, "   %s = 0x%2x 0x%2x 0x%2x\n",
             name,
             rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
}

void printStyleColors( GtkStyle* pStyle )
{
    static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };

    for( int i = 0; i < 5; i++ )
    {
        std::fprintf( stderr, "state %s colors:\n", pStates[i] );
        printColor( "bg     ", pStyle->bg[i] ); 
        printColor( "fg     ", pStyle->fg[i] ); 
        printColor( "light  ", pStyle->light[i] ); 
        printColor( "dark   ", pStyle->dark[i] ); 
        printColor( "mid    ", pStyle->mid[i] ); 
        printColor( "text   ", pStyle->text[i] ); 
        printColor( "base   ", pStyle->base[i] ); 
        printColor( "text_aa", pStyle->text_aa[i] ); 
    }
}
#endif

void GtkSalGraphics::updateSettings( AllSettings& rSettings )
{
    // get the widgets in place
    NWEnsureGTKMenu( m_nScreen );
    NWEnsureGTKMenubar( m_nScreen );
    NWEnsureGTKScrollbars( m_nScreen );
    NWEnsureGTKEditBox( m_nScreen );
    NWEnsureGTKTooltip( m_nScreen );
    
    gtk_widget_ensure_style( m_pWindow );
    GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
    
    StyleSettings aStyleSet = rSettings.GetStyleSettings();

#if OSL_DEBUG_LEVEL > 2
    printStyleColors( pStyle );
#endif
    
    // text colors
    Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
    aStyleSet.SetDialogTextColor( aTextColor );
    aStyleSet.SetButtonTextColor( aTextColor );
    aStyleSet.SetRadioCheckTextColor( aTextColor );
    aStyleSet.SetGroupTextColor( aTextColor );
    aStyleSet.SetLabelTextColor( aTextColor );
    aStyleSet.SetInfoTextColor( aTextColor );
    aStyleSet.SetWindowTextColor( aTextColor );
    aStyleSet.SetFieldTextColor( aTextColor );

    // Tooltip colors
    GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gTooltipPopup );
    aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
    aStyleSet.SetHelpTextColor( aTextColor );
    
    // mouse over text colors
    aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
    aStyleSet.SetButtonRolloverTextColor( aTextColor );
    aStyleSet.SetFieldRolloverTextColor( aTextColor );
    
    // background colors
    Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
    Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
    aStyleSet.Set3DColors( aBackColor );
    aStyleSet.SetFaceColor( aBackColor );
    aStyleSet.SetDialogColor( aBackColor );
    aStyleSet.SetWorkspaceColor( aBackColor );
    aStyleSet.SetFieldColor( aBackFieldColor );
    aStyleSet.SetWindowColor( aBackFieldColor );
//    aStyleSet.SetHelpColor( aBackColor );
    // ancient wisdom tells us a mystic algorithm how to set checked color
    if( aBackColor == COL_LIGHTGRAY )
        aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
    else
    {
        Color aColor2 = aStyleSet.GetLightColor();
        Color aCheck( (sal_uInt8)(((sal_uInt16)aBackColor.GetRed()+(sal_uInt16)aColor2.GetRed())/2),
                      (sal_uInt8)(((sal_uInt16)aBackColor.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2),
                      (sal_uInt8)(((sal_uInt16)aBackColor.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2)
                      );
        aStyleSet.SetCheckedColor( aCheck );
    }

    // highlighting colors
    Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
    Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
    aStyleSet.SetHighlightColor( aHighlightColor );
    aStyleSet.SetHighlightTextColor( aHighlightTextColor );

    if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
    {
        // hyperlink colors
        GdkColor *link_color = NULL;
        gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
        if (link_color)
        {
            aStyleSet.SetLinkColor(getColor(*link_color));
            gdk_color_free (link_color);
            link_color = NULL;
        }
        gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
        if (link_color)
        {
            aStyleSet.SetVisitedLinkColor(getColor(*link_color));
            gdk_color_free (link_color);
        }
    }

    // Tab colors
    aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
    Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
    aStyleSet.SetInactiveTabColor( aSelectedBackColor );

    // menu disabled entries handling
    aStyleSet.SetSkipDisabledInMenus( sal_True );
    // menu colors
    GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gMenuWidget );
    GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenuItemMenuWidget );
    GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenubarWidget );
    GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nScreen].gMenuItemMenuWidget) ) );
    
    aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
    aStyleSet.SetMenuBarColor( aBackColor );
    aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
    aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
    aStyleSet.SetMenuColor( aBackColor );
    aStyleSet.SetMenuTextColor( aTextColor );

    aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] );
    aStyleSet.SetMenuBarTextColor( aTextColor );
    
#if OSL_DEBUG_LEVEL > 1
    std::fprintf( stderr, "==\n" );
    std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
    std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
    std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
    std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
    std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
    std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
#endif

    // Awful hack for menu separators in the Sonar and similar themes.
    // If the menu color is not too dark, and the menu text color is lighter,
    // make the "light" color lighter than the menu color and the "shadow"
    // color darker than it.
    if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
	 aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
    {
      Color temp = aStyleSet.GetMenuColor();
      temp.IncreaseLuminance( 8 );
      aStyleSet.SetLightColor( temp );
      temp = aStyleSet.GetMenuColor();
      temp.DecreaseLuminance( 16 );
      aStyleSet.SetShadowColor( temp );
    }
    
    aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
    aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] );
    if( aHighlightColor == aHighlightTextColor )
        aHighlightTextColor = (aHighlightColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK );
    aStyleSet.SetMenuHighlightColor( aHighlightColor );
    aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
    
    // UI font
    OString	aFamily		= pango_font_description_get_family( pStyle->font_desc );
    int nPangoHeight	= pango_font_description_get_size( pStyle->font_desc );
    PangoStyle	eStyle	= pango_font_description_get_style( pStyle->font_desc );
    PangoWeight	eWeight	= pango_font_description_get_weight( pStyle->font_desc );
    PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
    
    psp::FastPrintFontInfo aInfo;
    // set family name
    aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
    // set italic
    switch( eStyle )
    {
        case PANGO_STYLE_NORMAL:	aInfo.m_eItalic = psp::italic::Upright;break;
        case PANGO_STYLE_ITALIC:	aInfo.m_eItalic = psp::italic::Italic;break;
        case PANGO_STYLE_OBLIQUE:	aInfo.m_eItalic = psp::italic::Oblique;break;
    }
    // set weight
    if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
        aInfo.m_eWeight = psp::weight::UltraLight;
    else if( eWeight <= PANGO_WEIGHT_LIGHT )
        aInfo.m_eWeight = psp::weight::Light;
    else if( eWeight <= PANGO_WEIGHT_NORMAL )
        aInfo.m_eWeight = psp::weight::Normal;
    else if( eWeight <= PANGO_WEIGHT_BOLD )
        aInfo.m_eWeight = psp::weight::Bold;
    else
        aInfo.m_eWeight = psp::weight::UltraBold;
    // set width
    switch( eStretch )
    {
        case PANGO_STRETCH_ULTRA_CONDENSED:	aInfo.m_eWidth = psp::width::UltraCondensed;break;
        case PANGO_STRETCH_EXTRA_CONDENSED:	aInfo.m_eWidth = psp::width::ExtraCondensed;break;
        case PANGO_STRETCH_CONDENSED:		aInfo.m_eWidth = psp::width::Condensed;break;
        case PANGO_STRETCH_SEMI_CONDENSED:	aInfo.m_eWidth = psp::width::SemiCondensed;break;
        case PANGO_STRETCH_NORMAL:			aInfo.m_eWidth = psp::width::Normal;break;
        case PANGO_STRETCH_SEMI_EXPANDED:	aInfo.m_eWidth = psp::width::SemiExpanded;break;
        case PANGO_STRETCH_EXPANDED:		aInfo.m_eWidth = psp::width::Expanded;break;
        case PANGO_STRETCH_EXTRA_EXPANDED:	aInfo.m_eWidth = psp::width::ExtraExpanded;break;
        case PANGO_STRETCH_ULTRA_EXPANDED:	aInfo.m_eWidth = psp::width::UltraExpanded;break;
    }

#if OSL_DEBUG_LEVEL > 1
    std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
#endif

    // match font to e.g. resolve "Sans"
    psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() );

#if OSL_DEBUG_LEVEL > 1
    std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
             aInfo.m_nID != 0 ? "succeeded" : "failed",
             OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
#endif
    
    sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
    int nPointHeight = 0;
    static gboolean(*pAbso)(const PangoFontDescription*) =
        (gboolean(*)(const PangoFontDescription*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" );

    if( pAbso && pAbso( pStyle->font_desc ) )
        nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
    else
        nPointHeight = nPangoHeight/PANGO_SCALE;
    
    Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
    if( aInfo.m_eWeight != psp::weight::Unknown )
        aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
    if( aInfo.m_eWidth != psp::width::Unknown )
        aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
    if( aInfo.m_eItalic != psp::italic::Unknown )
        aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
    if( aInfo.m_ePitch != psp::pitch::Unknown )
        aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );

    aStyleSet.SetAppFont( aFont );
    aStyleSet.SetHelpFont( aFont );
    aStyleSet.SetTitleFont( aFont );
    aStyleSet.SetFloatTitleFont( aFont );
    aStyleSet.SetMenuFont( aFont );
    aStyleSet.SetToolFont( aFont );
    aStyleSet.SetLabelFont( aFont );
    aStyleSet.SetInfoFont( aFont );
    aStyleSet.SetRadioCheckFont( aFont );
    aStyleSet.SetPushButtonFont( aFont );
    aStyleSet.SetFieldFont( aFont );
    aStyleSet.SetIconFont( aFont );
    aStyleSet.SetGroupFont( aFont );

    // get cursor blink time
    GtkSettings *pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gEditBoxWidget );
    gboolean blink = false;

    g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
    if( blink )
    {
        gint blink_time = STYLE_CURSOR_NOBLINKTIME;
        g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
        // set the blink_time if there is a setting and it is reasonable
        // else leave the default value
        if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
            aStyleSet.SetCursorBlinkTime( blink_time/2 );
    }
    else
        aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );

    gboolean showmenuicons = true;
    pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gImageMenuItem );
    g_object_get( pSettings, "gtk-menu-images", &showmenuicons, (char *)NULL );
    aStyleSet.SetUseImagesInMenus( showmenuicons );

    // set scrollbar settings
    gint slider_width = 14;
    gint trough_border = 1;
    gint min_slider_length = 21;
    
    // Grab some button style attributes
    gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
                          "slider-width", &slider_width,
                          "trough-border", &trough_border,
                          "min-slider-length", &min_slider_length,
                          (char *)NULL );
    gint magic = trough_border ? 1 : 0;
    aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
    aStyleSet.SetMinThumbSize( min_slider_length - magic );

    // preferred icon style
    gchar* pIconThemeName = NULL;
    g_object_get( gtk_settings_get_default(), "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
    aStyleSet.SetPreferredSymbolsStyleName( OUString::createFromAscii( pIconThemeName ) );
    g_free( pIconThemeName );

    //  FIXME: need some way of fetching toolbar icon size.
//	aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL );

    const cairo_font_options_t* pNewOptions = NULL;
    if( GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), m_nScreen ) )
    {
//#if !GTK_CHECK_VERSION(2,8,1)
#if !GTK_CHECK_VERSION(2,9,0)
	static cairo_font_options_t* (*gdk_screen_get_font_options)(GdkScreen*) = 
		(cairo_font_options_t*(*)(GdkScreen*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_font_options" );
    if( gdk_screen_get_font_options != NULL )
#endif
		pNewOptions = gdk_screen_get_font_options( pScreen );
    }
    aStyleSet.SetCairoFontOptions( pNewOptions );

    // finally update the collected settings
    rSettings.SetStyleSettings( aStyleSet );

    #if OSL_DEBUG_LEVEL > 1
    {    
        GtkSettings* pGtkSettings = gtk_settings_get_default();
        GValue aValue;
        memset( &aValue, 0, sizeof(GValue) );
        g_value_init( &aValue, G_TYPE_STRING );
        g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
        const gchar* pThemeName = g_value_get_string( &aValue );
        std::fprintf( stderr, "Theme name is \"%s\"\n", pThemeName );
        g_value_unset( &aValue );
    }
    #endif
    GtkSettings* pGtkSettings = gtk_settings_get_default();
    GValue aValue;
    memset( &aValue, 0, sizeof(GValue) );
    g_value_init( &aValue, G_TYPE_STRING );
    g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
    const gchar* pThemeName = g_value_get_string( &aValue );

    // default behaviour
    bNeedPixmapPaint = bGlobalNeedPixmapPaint;
    bToolbarGripWorkaround = false;
    bNeedButtonStyleAsEditBackgroundWorkaround = false;

    // setup some workarounds for "blueprint" theme
    if( pThemeName
        && (   strncasecmp( pThemeName, "blueprint", 9 ) == 0
            || strncasecmp( pThemeName, "Adwaita", 7 ) == 0 ))
    {
        bNeedButtonStyleAsEditBackgroundWorkaround = true;
        if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
        {
            // #i52570#, #i61532# workaround a weird paint issue;
            // on a Sunray Xserver sometimes painting buttons and edits
            // won't work when using the blueprint theme
            // not reproducible with simpler programs or other themes
            if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
            {
                bNeedPixmapPaint = true;
                bToolbarGripWorkaround = true;
            }
        }
    }
    // clean up
    g_value_unset( &aValue );
}


/************************************************************************
 * Create a GdkPixmap filled with the contents of an area of an Xlib window
 ************************************************************************/

GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect )
{
    // Create a new pixmap to hold the composite of the window background and the control
    GdkPixmap * pPixmap		= gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 ); 
	GdkGC *	 pPixmapGC	= gdk_gc_new( pPixmap );

    if( !pPixmap || !pPixmapGC )
    {
        if ( pPixmap )
            g_object_unref( pPixmap );
        if ( pPixmapGC )
            g_object_unref( pPixmapGC );
        std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" );
        return( NULL );
    }

    // Copy the background of the screen into a composite pixmap
    CopyScreenArea( GetXDisplay(),
              GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
              gdk_x11_drawable_get_xid(pPixmap),
              gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
              gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ),
              gdk_x11_gc_get_xgc(pPixmapGC),
              srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 );

    g_object_unref( pPixmapGC );
    return( pPixmap );
}




/************************************************************************
 * Copy an alpha pixmap to screen using a gc with clipping
 ************************************************************************/

sal_Bool GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect )
{
    // The GC can't be null, otherwise we'd have no clip region
    GC aFontGC = GetFontGC();
    if( aFontGC == NULL )
    {
        std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" );
        return( sal_False );
    }

    if ( !pPixmap )
        return( sal_False );

    // Copy the background of the screen into a composite pixmap
    CopyScreenArea( GetXDisplay(),
              GDK_DRAWABLE_XID(pPixmap),
              gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
              gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ),
              GetDrawable(), m_nScreen, GetVisual().GetDepth(),
              aFontGC,
              0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() );

    return( sal_True );
}


/************************************************************************
 * State conversion
 ************************************************************************/
static void NWConvertVCLStateToGTKState( ControlState nVCLState,
			GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
{
	*nGTKShadow = GTK_SHADOW_OUT;
	*nGTKState = GTK_STATE_INSENSITIVE;

	if ( nVCLState & CTRL_STATE_ENABLED )
	{
		if ( nVCLState & CTRL_STATE_PRESSED )
		{
			*nGTKState = GTK_STATE_ACTIVE;
			*nGTKShadow = GTK_SHADOW_IN;
		}
		else if ( nVCLState & CTRL_STATE_ROLLOVER )
		{
			*nGTKState = GTK_STATE_PRELIGHT;
			*nGTKShadow = GTK_SHADOW_OUT;
		}
		else
		{
			*nGTKState = GTK_STATE_NORMAL;
			*nGTKShadow = GTK_SHADOW_OUT;
		}
	}
}

/************************************************************************
 * Set widget flags
 ************************************************************************/
static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
{
	// Set to default state, then build up from there
	GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
	GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
	GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
	GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[(long)widget] );

	if ( nState & CTRL_STATE_DEFAULT )
		GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
	if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & CTRL_STATE_FOCUSED) )
		GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
	if ( nState & CTRL_STATE_ENABLED )
		GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
	gtk_widget_set_state( widget, nGtkState );
}

/************************************************************************
 * Widget ensure functions - make sure cached objects are valid
 ************************************************************************/

//-------------------------------------

static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen )
{
    NWFWidgetData& rData = gWidgetData[nScreen];
	if ( !rData.gCacheWindow || !rData.gDumbContainer )
	{
		if ( !rData.gCacheWindow )
        {
			rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
            GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
            if( pScreen )
                gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
        }
		if ( !rData.gDumbContainer )
			rData.gDumbContainer = gtk_fixed_new();
		gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
		gtk_widget_realize( rData.gDumbContainer );
		gtk_widget_realize( rData.gCacheWindow );
	}

	gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
	gtk_widget_realize( widget );
	gtk_widget_ensure_style( widget );

	// Store widget's default flags
	gWidgetDefaultFlags[ (long)widget ] = GTK_WIDGET_FLAGS( widget );
}

//-------------------------------------

static void NWEnsureGTKButton( int nScreen )
{
	if ( !gWidgetData[nScreen].gBtnWidget )
	{
		gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKRadio( int nScreen )
{
	if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
	{
		gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
		gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKCheck( int nScreen )
{
	if ( !gWidgetData[nScreen].gCheckWidget )
	{
		gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKScrollbars( int nScreen )
{
	if ( !gWidgetData[nScreen].gScrollHorizWidget )
	{
		gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
	}

	if ( !gWidgetData[nScreen].gScrollVertWidget )
	{
		gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKArrow( int nScreen )
{
	if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
	{
		gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
		gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
		gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
		gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
		gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
	}
}

//-------------------------------------

static void NWEnsureGTKEditBox( int nScreen )
{
	if ( !gWidgetData[nScreen].gEditBoxWidget )
	{
		gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKSpinButton( int nScreen )
{
	if ( !gWidgetData[nScreen].gSpinButtonWidget )
	{
		GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
		gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );

		//Setting non-editable means it doesn't blink, so there's no timeouts
		//running around to nobble us
		gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);

		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKNotebook( int nScreen )
{
	if ( !gWidgetData[nScreen].gNotebookWidget )
	{
		gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKOptionMenu( int nScreen )
{
	if ( !gWidgetData[nScreen].gOptionMenuWidget )
	{
		gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKCombo( int nScreen )
{
	if ( !gWidgetData[nScreen].gComboWidget )
	{
		gWidgetData[nScreen].gComboWidget = gtk_combo_new();

		// #i59129# Setting non-editable means it doesn't blink, so
        // there are no timeouts running around to nobble us
		gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);

		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
		// Must realize the ComboBox's children, since GTK
		// does not do this for us in GtkCombo::gtk_widget_realize()
		gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
		gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
	}
}

//-------------------------------------

static void NWEnsureGTKScrolledWindow( int nScreen )
{
	if ( !gWidgetData[nScreen].gScrolledWindowWidget )
	{
		GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
		GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );

		gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
	}
}

//-------------------------------------

static void NWEnsureGTKToolbar( int nScreen )
{
    if( !gWidgetData[nScreen].gToolbarWidget )
    {
        gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
        NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
        gWidgetData[nScreen].gToolbarButtonWidget = gtk_button_new();
        gWidgetData[nScreen].gToolbarToggleWidget = gtk_toggle_button_new();
        
        GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
        gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
        gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
			                  "button_relief", &aRelief,
                              (char *)NULL);
                              
        gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
        GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
        GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
        NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );

        gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarToggleWidget), aRelief );
        GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_FOCUS );
        GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_DEFAULT );
        NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarToggleWidget, nScreen );        
    }
    if( ! gWidgetData[nScreen].gHandleBoxWidget )
    {
        gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
        NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
    }
}

//-------------------------------------

static void NWEnsureGTKMenubar( int nScreen )
{
    if( !gWidgetData[nScreen].gMenubarWidget )
    {
        gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
        gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
        gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
        gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
        NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
        gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
        
        // do what NWAddWidgetToCacheWindow does except adding to def container
        gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
        gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );

        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenubarWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
    }
}

static void NWEnsureGTKMenu( int nScreen )
{
    if( !gWidgetData[nScreen].gMenuWidget )
    {
        gWidgetData[nScreen].gMenuWidget              = gtk_menu_new();
        gWidgetData[nScreen].gMenuItemMenuWidget      = gtk_menu_item_new_with_label( "b" );
        gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
        gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
        gWidgetData[nScreen].gImageMenuItem           = gtk_image_menu_item_new();
        
        gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
        gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
        gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
        gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
        
        // do what NWAddWidgetToCacheWindow does except adding to def container
        gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
        gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );

        gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
        gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );

        gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
        gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );

        gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
        gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );

        gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
        gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );

        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemCheckMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemRadioMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
        gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gImageMenuItem ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
    }
}

static void NWEnsureGTKTooltip( int nScreen )
{
    if( !gWidgetData[nScreen].gTooltipPopup )
    {
        gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
        GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
        if( pScreen )
            gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
        gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
        gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
        gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
    }
}

static void NWEnsureGTKProgressBar( int nScreen )
{
    if( !gWidgetData[nScreen].gProgressBar )
    {
        gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
    }
}

static void NWEnsureGTKTreeView( int nScreen )
{
    if( !gWidgetData[nScreen].gTreeView )
    {
        gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
    }
}

static void NWEnsureGTKSlider( int nScreen )
{
    if( !gWidgetData[nScreen].gHScale )
    {
        gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
    }
    if( !gWidgetData[nScreen].gVScale )
    {
        gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
		NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
    }
}