diff options
Diffstat (limited to 'vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx')
-rw-r--r-- | vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx | 4129 |
1 files changed, 4129 insertions, 0 deletions
diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx new file mode 100644 index 000000000000..cdc72485ae6c --- /dev/null +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -0,0 +1,4129 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_vcl.hxx" + +#include "plugins/gtk/gtkframe.hxx" +#include "plugins/gtk/gtkdata.hxx" +#include "plugins/gtk/gtkinst.hxx" +#include "plugins/gtk/gtkgdi.hxx" + +#include "pspgraphics.h" + +#include <cstdio> +#include <cmath> +#include <vector> +#include <algorithm> +#include <hash_map> + +#include "saldata.hxx" +#include "saldisp.hxx" +#include "vcl/svapp.hxx" + +typedef struct _cairo_font_options cairo_font_options_t; + +// initialize statics +BOOL GtkSalGraphics::bThemeChanged = TRUE; +BOOL GtkSalGraphics::bNeedPixmapPaint = FALSE; +BOOL GtkSalGraphics::bGlobalNeedPixmapPaint = FALSE; +BOOL GtkSalGraphics::bToolbarGripWorkaround = FALSE; +BOOL GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = 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; } + + 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 ); +} + +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 TRUE; + } + } + return 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; + + 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(); +} + +void GtkSalGraphics::BeginSetClipRegion( ULONG nCount ) +{ + m_aClipRegion.SetNull(); + X11SalGraphics::BeginSetClipRegion( nCount ); +} + +BOOL GtkSalGraphics::unionClipRegion( long nX, long nY, long nWidth, long nHeight ) +{ + Rectangle aRect( Point( nX, nY ), Size( nWidth, nHeight ) ); + m_aClipRegion.Union( aRect ); + return X11SalGraphics::unionClipRegion( nX, nY, nWidth, nHeight ); +} + +bool GtkSalGraphics::unionClipRegion( const ::basegfx::B2DPolyPolygon& ) +{ + // TODO: implement and advertise OutDevSupport_B2DClip support + return false; +} + +void GtkSalGraphics::EndSetClipRegion() +{ + if( m_aClipRegion.IsEmpty() ) + m_aClipRegion.SetNull(); + X11SalGraphics::EndSetClipRegion(); +} + +void GtkSalGraphics::copyBits( const SalTwoRect* pPosAry, + 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( pPosAry, pSrcGraphics ); + if( pFrame && pFrame->getBackgroundPixmap() != None ) + XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(), + aWin, + pFrame->getBackgroundPixmap() ); +} + +/* + * IsNativeControlSupported() + * + * Returns TRUE if the platform supports native + * drawing of the control defined by nPart + */ +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( TRUE ); + + return( FALSE ); +} + + +/* + * HitTestNativeControl() + * + * bIsInside is set to 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. + */ +BOOL GtkSalGraphics::hitTestNativeControl( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + const Point& aPos, + 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 = 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.GetBoundRect() ); + aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion.GetBoundRect() ); + + 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 ( TRUE ); + } + + if( IsNativeControlSupported(nType, nPart) ) + { + rIsInside = rControlRegion.IsInside( aPos ); + return( TRUE ); + } + else + { + return( 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) + */ +BOOL GtkSalGraphics::drawNativeControl( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + const OUString& rCaption ) +{ + if( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) && + aValue.getTristateVal() == BUTTONVALUE_MIXED ) + { + return drawNativeMixedStateCheck( nType, nPart, rControlRegion, nState, aValue, rCaption ); + } + + BOOL returnVal = FALSE; + // get a GC with current clipping region set + SelectFont(); + + + // 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 = FALSE; + } + + Rectangle aCtrlRect = rControlRegion.GetBoundRect(); + 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 FALSE; + gdkDrawable = GDK_DRAWABLE( pixmap ); + aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() ); + aClip.push_back( aCtrlRect ); + } + else + { + RegionHandle aHdl = aClipRegion.BeginEnumRects(); + Rectangle aPaintRect; + while( aClipRegion.GetNextEnumRect( 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 = 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 ); +} + +BOOL GtkSalGraphics::drawNativeMixedStateCheck( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + const OUString& rCaption ) +{ + // need to emulate something for mixed state + + // do this via pixmap since some themes don't care for regions + bool bOldNeedPixmapPaint = bNeedPixmapPaint; + bNeedPixmapPaint = true; + + Rectangle aCtrlRect = rControlRegion.GetBoundRect(); + BOOL returnVal = FALSE; + SelectFont(); + + // draw upper half in off state + const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_OFF ); + XLIB_Region aRegion = XCreateRegion(); + XRectangle aXRect = { aCtrlRect.Left(), aCtrlRect.Top(), aCtrlRect.GetWidth(), aCtrlRect.GetHeight() }; + const unsigned short nH = aXRect.height/2; + aXRect.height -= nH; + XUnionRectWithRegion( &aXRect, aRegion, aRegion ); + SetClipRegion( pFontGC_, aRegion ); + XDestroyRegion( aRegion ); + + returnVal = drawNativeControl( nType, nPart, rControlRegion, nState, aValue, rCaption ); + + if( returnVal ) + { + // draw lower half in on state + const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_ON ); + aXRect.y += nH; + aRegion = XCreateRegion(); + XUnionRectWithRegion( &aXRect, aRegion, aRegion ); + SetClipRegion( pFontGC_, aRegion ); + XDestroyRegion( aRegion ); + returnVal = drawNativeControl( nType, nPart, rControlRegion, nState, aValue, rCaption ); + } + + // clean up + bNeedPixmapPaint = bOldNeedPixmapPaint; + const_cast<ImplControlValue&>(aValue).setTristateVal( BUTTONVALUE_MIXED ); + SetClipRegion( pFontGC_ ); + 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) + */ +BOOL GtkSalGraphics::drawNativeControlText( ControlType, + ControlPart, + const Region&, + ControlState, + const ImplControlValue&, + const OUString& ) +{ + return( FALSE ); +} + + +/* + * GetNativeControlRegion() + * + * If the return value is 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) + */ +BOOL GtkSalGraphics::getNativeControlRegion( ControlType nType, + ControlPart nPart, + const Region& rControlRegion, + ControlState nState, + const ImplControlValue& aValue, + const OUString& rCaption, + Region &rNativeBoundingRegion, + Region &rNativeContentRegion ) +{ + BOOL returnVal = FALSE; + + if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) + && (rControlRegion.GetBoundRect().GetWidth() > 16) + && (rControlRegion.GetBoundRect().GetHeight() > 16) ) + { + rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), + nState, aValue, rCaption ); + rNativeContentRegion = rControlRegion; + + returnVal = TRUE; + } + if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) ) + { + rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState, + aValue, rCaption ); + rNativeContentRegion = rNativeBoundingRegion; + + returnVal = TRUE; + } + if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) ) + { + + rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState, + aValue, rCaption ); + rNativeContentRegion = rNativeBoundingRegion; + + returnVal = TRUE; + } + if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) ) + { + rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion.GetBoundRect(), nState, + aValue, rCaption ); + rNativeContentRegion = rNativeBoundingRegion; + + returnVal = 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.GetBoundRect(), nState, aValue, rCaption ); + rNativeContentRegion = rNativeBoundingRegion; + returnVal = 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.GetBoundRect() ); + rNativeContentRegion = rNativeBoundingRegion; + + returnVal = 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.GetBoundRect(); + aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(), + Size( aMenuBarRect.GetWidth(), aReq.height+1 ) ); + rNativeBoundingRegion = Region( aMenuBarRect ); + rNativeContentRegion = rNativeBoundingRegion; + returnVal = 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.GetBoundRect().GetHeight()-indicator_size)/2), + Size( indicator_size, indicator_size ) ); + rNativeContentRegion = Region( aIndicatorRect ); + returnVal = 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.GetBoundRect().GetHeight()-indicator_size)/2), + Size( indicator_size, indicator_size ) ); + rNativeContentRegion = Region( aIndicatorRect ); + returnVal = 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.GetBoundRect(); + aEditRect = Rectangle( aEditRect.TopLeft(), + Size( aEditRect.GetWidth(), aReq.height+1 ) ); + rNativeBoundingRegion = Region( aEditRect ); + rNativeContentRegion = rNativeBoundingRegion; + returnVal = 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.GetBoundRect() ); + 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 = Region( aRect ); + returnVal = TRUE; + } + + return( returnVal ); +} + + +/************************************************************************ + * Individual control drawing functions + ************************************************************************/ +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; + BOOL bDrawFocus = 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 = 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( 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; + BOOL bDrawFocus = 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 = 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 ); +} + +//------------------------------------- + +BOOL GtkSalGraphics::NWPaintGTKRadio( 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); + 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 = 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( TRUE ); +} + +//------------------------------------- + +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) ? TRUE : FALSE; + 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 : 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( 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 + ) ); +} + +BOOL GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart, + const Rectangle& rControlRectangle, + const clipList&, + ControlState nState, + const ImplControlValue& aValue, + const OUString& ) +{ + ScrollbarValue* pScrollbarVal = (ScrollbarValue *)(aValue.getOptionalVal()); + 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( 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 ); + } + + 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 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, 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, 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, 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, TRUE, + x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(), + arrowRect.GetWidth(), arrowRect.GetHeight() ); + } + + if( !NWRenderPixmapToScreen(pixmap, pixmapRect) ) + { + g_object_unref( pixmap ); + return( FALSE ); + } + g_object_unref( pixmap ); + + return( 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 ); +} + +//------------------------------------- + +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( 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() ); + +} + + + +//------------------------------------- + +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; + SpinbuttonValue * pSpinVal = (SpinbuttonValue *)(aValue.getOptionalVal()); + 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( 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( FALSE ); + } + + g_object_unref( pixmap ); + return( 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, TRUE, + (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()), + arrowRect.GetWidth(), arrowRect.GetHeight() ); +} + + +//------------------------------------- + +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, TRUE, + x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()), + arrowRect.GetWidth(), arrowRect.GetHeight() ); + } + + return( 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 ); +} + +//------------------------------------- + + + +BOOL GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, + const Rectangle& rControlRectangle, + const clipList&, + ControlState nState, + const ImplControlValue& aValue, + const OUString& ) +{ + GdkPixmap * pixmap; + Rectangle pixmapRect; + Rectangle tabRect; + TabitemValue * pTabitemValue = (TabitemValue *)(aValue.getOptionalVal()); + 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 ( !pTabitemValue && (nType==CTRL_TAB_ITEM) ) + { + std::fprintf( stderr, "NWPaintGTKTabItem() received a NULL TabitemValue. Cannot draw native tab\n" ); + 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 ) + { + 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 ); + + BOOL bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect); + g_object_unref( pixmap ); + return bSuccess; +} + +//------------------------------------- + +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( TRUE ); +} + +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; + const gchar* pButtonDetail = "button"; + 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 + ToolbarValue* pVal = (ToolbarValue*)aValue.getOptionalVal(); + if( pVal ) + { + 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; + // special case stateType value for depressed toggle buttons + // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state) + if( ! (nState & (CTRL_STATE_PRESSED|CTRL_STATE_ROLLOVER)) ) + stateType = GTK_STATE_ACTIVE; + pButtonDetail = "togglebutton"; + bPaintButton = true; + } + + 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, pButtonDetail, x, y, w, h ); + } + } + } + + return( TRUE ); +} + +//---- + +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( TRUE ); +} + +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 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( TRUE ); +} + +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( TRUE ); +} + +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 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 ); + + BOOL bRet = NWRenderPixmapToScreen( pixmap, aRect ); + g_object_unref( pixmap ); + + return bRet; +} + +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 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 + ); + } + } + + BOOL bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle ); + g_object_unref( pixmap ); + + return bRet; +} + +BOOL GtkSalGraphics::NWPaintGTKSlider( + GdkDrawable*, + ControlType, ControlPart nPart, + const Rectangle& rControlRectangle, + const clipList&, + ControlState nState, const ImplControlValue& rValue, + const OUString& ) +{ + NWEnsureGTKSlider( m_nScreen ); + + gint w, h; + w = rControlRectangle.GetWidth(); + h = rControlRectangle.GetHeight(); + + SliderValue* pVal = (SliderValue*)rValue.getOptionalVal(); + + GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle ); + if( ! pixmap ) + return FALSE; + + (void)pVal; + + 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 + + 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( (BYTE)(((USHORT)aBackColor.GetRed()+(USHORT)aColor2.GetRed())/2), + (BYTE)(((USHORT)aBackColor.GetGreen()+(USHORT)aColor2.GetGreen())/2), + (BYTE)(((USHORT)aBackColor.GetBlue()+(USHORT)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( 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 ) + { + 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 + ************************************************************************/ + +BOOL GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect ) +{ + // The GC can't be null, otherwise we'd have no clip region + if( SelectFont() == NULL ) + { + std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" ); + return( FALSE ); + } + + if ( !pPixmap ) + return( 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(), + SelectFont(), + 0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() ); + + return( 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 ); + } +} |