xref: /trunk/main/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include "vcl/svapp.hxx"
32 
33 #include "unx/gtk/gtkframe.hxx"
34 #include "unx/gtk/gtkdata.hxx"
35 #include "unx/gtk/gtkinst.hxx"
36 #include "unx/gtk/gtkgdi.hxx"
37 
38 #include "unx/pspgraphics.h"
39 #include "unx/saldata.hxx"
40 #include "unx/saldisp.hxx"
41 
42 #include <cstdio>
43 #include <cmath>
44 #include <vector>
45 #include <algorithm>
46 #include <hash_map>
47 
48 typedef struct _cairo_font_options cairo_font_options_t;
49 
50 // initialize statics
51 sal_Bool GtkSalGraphics::bThemeChanged = sal_True;
52 sal_Bool GtkSalGraphics::bNeedPixmapPaint = sal_False;
53 sal_Bool GtkSalGraphics::bGlobalNeedPixmapPaint = sal_False;
54 sal_Bool GtkSalGraphics::bToolbarGripWorkaround = sal_False;
55 sal_Bool GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround = sal_False;
56 
57 GtkSalGraphics::~GtkSalGraphics()
58 {
59 }
60 
61 
62 using namespace rtl;
63 
64 /*************************************
65  * Cached native widget objects
66  *************************************/
67 class NWPixmapCacheList;
68 class NWPixmapCache;
69 struct NWFWidgetData
70 {
71     GtkWidget * gCacheWindow;
72     GtkWidget * gDumbContainer;
73 
74     GtkWidget * gBtnWidget;
75     GtkWidget * gRadioWidget;
76     GtkWidget * gRadioWidgetSibling;
77     GtkWidget * gCheckWidget;
78     GtkWidget * gScrollHorizWidget;
79     GtkWidget * gScrollVertWidget;
80     GtkWidget * gArrowWidget;
81     GtkWidget * gDropdownWidget;
82     GtkWidget * gEditBoxWidget;
83     GtkWidget * gSpinButtonWidget;
84     GtkWidget * gNotebookWidget;
85     GtkWidget * gOptionMenuWidget;
86     GtkWidget * gComboWidget;
87     GtkWidget * gScrolledWindowWidget;
88     GtkWidget *  gToolbarWidget;
89     GtkWidget *  gToolbarButtonWidget;
90     GtkWidget *  gToolbarToggleWidget;
91     GtkWidget *  gHandleBoxWidget;
92     GtkWidget *  gMenubarWidget;
93     GtkWidget *  gMenuItemMenubarWidget;
94     GtkWidget *  gMenuWidget;
95     GtkWidget *  gMenuItemMenuWidget;
96     GtkWidget *  gMenuItemCheckMenuWidget;
97     GtkWidget *  gMenuItemRadioMenuWidget;
98     GtkWidget *  gImageMenuItem;
99     GtkWidget *  gTooltipPopup;
100     GtkWidget *  gProgressBar;
101     GtkWidget *  gTreeView;
102     GtkWidget *  gHScale;
103     GtkWidget *  gVScale;
104 
105     NWPixmapCacheList* gNWPixmapCacheList;
106     NWPixmapCache* gCacheTabItems;
107     NWPixmapCache* gCacheTabPages;
108 
109     NWFWidgetData() :
110         gCacheWindow( NULL ),
111         gDumbContainer( NULL ),
112         gBtnWidget( NULL ),
113         gRadioWidget( NULL ),
114         gRadioWidgetSibling( NULL ),
115         gCheckWidget( NULL ),
116         gScrollHorizWidget( NULL ),
117         gScrollVertWidget( NULL ),
118         gArrowWidget( NULL ),
119         gDropdownWidget( NULL ),
120         gEditBoxWidget( NULL ),
121         gSpinButtonWidget( NULL ),
122         gNotebookWidget( NULL ),
123         gOptionMenuWidget( NULL ),
124         gComboWidget( NULL ),
125         gScrolledWindowWidget( NULL ),
126         gToolbarWidget( NULL ),
127         gToolbarButtonWidget( NULL ),
128         gToolbarToggleWidget( NULL ),
129         gHandleBoxWidget( NULL ),
130         gMenubarWidget( NULL ),
131         gMenuItemMenubarWidget( NULL ),
132         gMenuWidget( NULL ),
133         gMenuItemMenuWidget( NULL ),
134         gMenuItemCheckMenuWidget( NULL ),
135         gMenuItemRadioMenuWidget( NULL ),
136         gImageMenuItem( NULL ),
137         gTooltipPopup( NULL ),
138         gProgressBar( NULL ),
139         gTreeView( NULL ),
140         gHScale( NULL ),
141         gVScale( NULL ),
142         gNWPixmapCacheList( NULL ),
143         gCacheTabItems( NULL ),
144         gCacheTabPages( NULL )
145     {}
146 };
147 
148 // Keep a hash table of Widgets->default flags so that we can
149 // easily and quickly reset each to a default state before using
150 // them
151 static std::hash_map<long, guint>   gWidgetDefaultFlags;
152 static std::vector<NWFWidgetData>   gWidgetData;
153 
154 static const GtkBorder aDefDefBorder        = { 1, 1, 1, 1 };
155 
156 // Some GTK defaults
157 #define MIN_ARROW_SIZE                  11
158 #define BTN_CHILD_SPACING               1
159 #define MIN_SPIN_ARROW_WIDTH                6
160 
161 
162 static void NWEnsureGTKRadio            ( int nScreen );
163 static void NWEnsureGTKButton           ( int nScreen );
164 static void NWEnsureGTKCheck            ( int nScreen );
165 static void NWEnsureGTKScrollbars       ( int nScreen );
166 static void NWEnsureGTKArrow            ( int nScreen );
167 static void NWEnsureGTKEditBox          ( int nScreen );
168 static void NWEnsureGTKSpinButton       ( int nScreen );
169 static void NWEnsureGTKNotebook         ( int nScreen );
170 static void NWEnsureGTKOptionMenu       ( int nScreen );
171 static void NWEnsureGTKCombo            ( int nScreen );
172 static void NWEnsureGTKScrolledWindow   ( int nScreen );
173 static void NWEnsureGTKToolbar          ( int nScreen );
174 static void NWEnsureGTKMenubar          ( int nScreen );
175 static void NWEnsureGTKMenu             ( int nScreen );
176 static void NWEnsureGTKTooltip          ( int nScreen );
177 static void NWEnsureGTKProgressBar      ( int nScreen );
178 static void NWEnsureGTKTreeView         ( int nScreen );
179 static void NWEnsureGTKSlider           ( int nScreen );
180 
181 static void NWConvertVCLStateToGTKState( ControlState nVCLState, GtkStateType* nGTKState, GtkShadowType* nGTKShadow );
182 static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen );
183 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState );
184 
185 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow );
186 
187 /*
188  * Individual helper functions
189  *
190  */
191 
192 //---
193 static Rectangle NWGetButtonArea( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
194                                 const ImplControlValue& aValue, const OUString& rCaption );
195 
196 //---
197 static Rectangle NWGetEditBoxPixmapRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
198                             const ImplControlValue& aValue, const OUString& rCaption );
199 
200 static void NWPaintOneEditBox( int nScreen, GdkDrawable * gdkDrawable, GdkRectangle *gdkRect,
201                                ControlType nType, ControlPart nPart, Rectangle aEditBoxRect,
202                                ControlState nState, const ImplControlValue& aValue,
203                                const OUString& rCaption );
204 
205 //---
206 static Rectangle NWGetSpinButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
207                             const ImplControlValue& aValue, const OUString& rCaption );
208 
209 static void NWPaintOneSpinButton( int nScreen, GdkPixmap * pixmap, ControlType nType, ControlPart nPart, Rectangle aAreaRect,
210                             ControlState nState, const ImplControlValue& aValue,
211                             const OUString& rCaption );
212 //---
213 static Rectangle NWGetComboBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
214                             const ImplControlValue& aValue, const OUString& rCaption );
215 
216 //---
217 static Rectangle NWGetListBoxButtonRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
218                             const ImplControlValue& aValue, const OUString& rCaption );
219 
220 static Rectangle NWGetListBoxIndicatorRect( int nScreen, ControlType nType, ControlPart nPart, Rectangle aAreaRect, ControlState nState,
221                             const ImplControlValue& aValue, const OUString& rCaption );
222 
223 static Rectangle NWGetToolbarRect( int nScreen,
224                                    ControlType nType,
225                                    ControlPart nPart,
226                                    Rectangle aAreaRect,
227                                    ControlState nState,
228                                    const ImplControlValue& aValue,
229                                    const OUString& rCaption );
230 //---
231 
232 static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect );
233 //---
234 
235 /*********************************************************
236  * PixmapCache
237  *********************************************************/
238 
239 // as some native widget drawing operations are pretty slow
240 // with certain themes (eg tabpages)
241 // this cache can be used to cache the corresponding pixmap
242 // see NWPaintGTKTabItem
243 
244 class NWPixmapCacheData
245 {
246 public:
247     ControlType m_nType;
248     ControlState m_nState;
249     Rectangle   m_pixmapRect;
250     GdkPixmap*  m_pixmap;
251 
252     NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {}
253     ~NWPixmapCacheData()
254         { SetPixmap( NULL ); };
255     void SetPixmap( GdkPixmap* pPixmap );
256 };
257 
258 class NWPixmapCache
259 {
260     int m_size;
261     int m_idx;
262     int m_screen;
263     NWPixmapCacheData* pData;
264 public:
265     NWPixmapCache( int nScreen );
266     ~NWPixmapCache();
267 
268     void SetSize( int n)
269         { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; }
270     int GetSize() { return m_size; }
271 
272     sal_Bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap );
273     void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap );
274 
275     void ThemeChanged();
276 };
277 
278 class NWPixmapCacheList
279 {
280 public:
281     ::std::vector< NWPixmapCache* > mCaches;
282 
283     void AddCache( NWPixmapCache *pCache );
284     void RemoveCache( NWPixmapCache *pCache );
285     void ThemeChanged();
286 };
287 
288 // --- implementation ---
289 
290 void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap )
291 {
292     if( m_pixmap )
293         g_object_unref( m_pixmap );
294 
295     m_pixmap = pPixmap;
296 
297     if( m_pixmap )
298         g_object_ref( m_pixmap );
299 }
300 
301 
302 NWPixmapCache::NWPixmapCache( int nScreen )
303 {
304     m_idx = 0;
305     m_size = 0;
306     m_screen = nScreen;
307     pData = NULL;
308     if( gWidgetData[m_screen].gNWPixmapCacheList )
309         gWidgetData[m_screen].gNWPixmapCacheList->AddCache(this);
310 }
311 NWPixmapCache::~NWPixmapCache()
312 {
313     if( gWidgetData[m_screen].gNWPixmapCacheList )
314         gWidgetData[m_screen].gNWPixmapCacheList->RemoveCache(this);
315     delete[] pData;
316 }
317 void NWPixmapCache::ThemeChanged()
318 {
319     // throw away cached pixmaps
320     int i;
321     for(i=0; i<m_size; i++)
322         pData[i].SetPixmap( NULL );
323 }
324 
325 sal_Bool  NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap )
326 {
327     aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
328     int i;
329     for(i=0; i<m_size; i++)
330     {
331         if( pData[i].m_nType == aType &&
332             pData[i].m_nState == aState &&
333             pData[i].m_pixmapRect.GetWidth() == r_pixmapRect.GetWidth() &&
334             pData[i].m_pixmapRect.GetHeight() == r_pixmapRect.GetHeight() &&
335             pData[i].m_pixmap != NULL )
336         {
337             *pPixmap = pData[i].m_pixmap;
338             return sal_True;
339         }
340     }
341     return sal_False;
342 }
343 
344 void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap )
345 {
346     if( !(aState & CTRL_CACHING_ALLOWED) )
347         return;
348 
349     aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag
350     m_idx = (m_idx+1) % m_size; // just wrap
351     pData[m_idx].m_nType = aType;
352     pData[m_idx].m_nState = aState;
353     pData[m_idx].m_pixmapRect = r_pixmapRect;
354     pData[m_idx].SetPixmap( pPixmap );
355 }
356 
357 
358 void NWPixmapCacheList::AddCache( NWPixmapCache* pCache )
359 {
360     mCaches.push_back( pCache );
361 }
362 void NWPixmapCacheList::RemoveCache( NWPixmapCache* pCache )
363 {
364     ::std::vector< NWPixmapCache* >::iterator p;
365     p = ::std::find( mCaches.begin(), mCaches.end(), pCache );
366     if( p != mCaches.end() )
367         mCaches.erase( p );
368 }
369 void NWPixmapCacheList::ThemeChanged( )
370 {
371     ::std::vector< NWPixmapCache* >::iterator p = mCaches.begin();
372     while( p != mCaches.end() )
373     {
374         (*p)->ThemeChanged();
375         p++;
376     }
377 }
378 
379 
380 /*********************************************************
381  * Make border manipulation easier
382  *********************************************************/
383 inline void NW_gtk_border_set_from_border( GtkBorder& aDst, const GtkBorder * pSrc )
384 {
385     aDst.left       = pSrc->left;
386     aDst.top        = pSrc->top;
387     aDst.right  = pSrc->right;
388     aDst.bottom = pSrc->bottom;
389 }
390 
391 
392 /*********************************************************
393  * Initialize GTK and local stuff
394  *********************************************************/
395 void GtkData::initNWF( void )
396 {
397     ImplSVData* pSVData = ImplGetSVData();
398 
399     // draw no border for popup menus (NWF draws its own)
400     pSVData->maNWFData.mbFlatMenu = true;
401 
402     // draw separate buttons for toolbox dropdown items
403     pSVData->maNWFData.mbToolboxDropDownSeparate = true;
404 
405     // small extra border around menu items
406     pSVData->maNWFData.mnMenuFormatExtraBorder = 1;
407 
408     // draw toolbars in separate lines
409     pSVData->maNWFData.mbDockingAreaSeparateTB = true;
410 
411     // open first menu on F10
412     pSVData->maNWFData.mbOpenMenuOnF10 = true;
413 
414     // omit GetNativeControl while painting (see brdwin.cxx)
415     pSVData->maNWFData.mbCanDrawWidgetAnySize = true;
416 
417     int nScreens = GetX11SalData()->GetDisplay()->GetScreenCount();
418     gWidgetData = std::vector<NWFWidgetData>( nScreens );
419     for( int i = 0; i < nScreens; i++ )
420         gWidgetData[i].gNWPixmapCacheList = new NWPixmapCacheList;
421 
422 
423     if( SalGetDesktopEnvironment().equalsAscii( "KDE" ) )
424     {
425         // #i97196# ensure a widget exists and the style engine was loaded
426         NWEnsureGTKButton( 0 );
427         if( g_type_from_name( "QtEngineStyle" ) )
428         {
429             // KDE 3.3 invented a bug in the qt<->gtk theme engine
430             // that makes direct rendering impossible: they totally
431             // ignore the clip rectangle passed to the paint methods
432             GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
433         }
434     }
435     static const char* pEnv = getenv( "SAL_GTK_USE_PIXMAPPAINT" );
436     if( pEnv && *pEnv )
437         GtkSalGraphics::bNeedPixmapPaint = GtkSalGraphics::bGlobalNeedPixmapPaint = true;
438 
439     #if OSL_DEBUG_LEVEL > 1
440     std::fprintf( stderr, "GtkPlugin: using %s NWF\n",
441              GtkSalGraphics::bNeedPixmapPaint ? "offscreen" : "direct" );
442     #endif
443 }
444 
445 
446 /*********************************************************
447  * Release GTK and local stuff
448  *********************************************************/
449 void GtkData::deInitNWF( void )
450 {
451 
452     for( unsigned int i = 0; i < gWidgetData.size(); i++ )
453     {
454         // free up global widgets
455         // gtk_widget_destroy will in turn destroy the child hierarchy
456         // so only destroy disjunct hierachies
457         if( gWidgetData[i].gCacheWindow )
458             gtk_widget_destroy( gWidgetData[i].gCacheWindow );
459         if( gWidgetData[i].gMenuWidget )
460             gtk_widget_destroy( gWidgetData[i].gMenuWidget );
461         if( gWidgetData[i].gTooltipPopup )
462             gtk_widget_destroy( gWidgetData[i].gTooltipPopup );
463         delete gWidgetData[i].gCacheTabPages;
464         gWidgetData[i].gCacheTabPages = NULL;
465         delete gWidgetData[i].gCacheTabItems;
466         gWidgetData[i].gCacheTabItems = NULL;
467         delete gWidgetData[i].gNWPixmapCacheList;
468         gWidgetData[i].gNWPixmapCacheList = NULL;
469     }
470 }
471 
472 
473 /**********************************************************
474  * track clip region
475  **********************************************************/
476 void GtkSalGraphics::ResetClipRegion()
477 {
478     m_aClipRegion.SetNull();
479     X11SalGraphics::ResetClipRegion();
480 }
481 
482 bool GtkSalGraphics::setClipRegion( const Region& i_rClip )
483 {
484     m_aClipRegion = i_rClip;
485     bool bRet = X11SalGraphics::setClipRegion( m_aClipRegion );
486     if( m_aClipRegion.IsEmpty() )
487         m_aClipRegion.SetNull();
488     return bRet;
489 }
490 
491 void GtkSalGraphics::copyBits( const SalTwoRect* pPosAry,
492                                SalGraphics* pSrcGraphics )
493 {
494     GtkSalFrame* pFrame = GetGtkFrame();
495     XLIB_Window aWin = None;
496     if( pFrame && m_pWindow )
497     {
498         /* #i64117# some themes set the background pixmap VERY frequently */
499         GdkWindow* pWin = GTK_WIDGET(m_pWindow)->window;
500         if( pWin )
501         {
502             aWin = GDK_WINDOW_XWINDOW(pWin);
503             if( aWin != None )
504                 XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
505                                             aWin,
506                                             None );
507         }
508     }
509     X11SalGraphics::copyBits( pPosAry, pSrcGraphics );
510     if( pFrame && pFrame->getBackgroundPixmap() != None )
511         XSetWindowBackgroundPixmap( pFrame->getDisplay()->GetDisplay(),
512                                     aWin,
513                                     pFrame->getBackgroundPixmap() );
514 }
515 
516 /*
517  * IsNativeControlSupported()
518  *
519  *  Returns sal_True if the platform supports native
520  *  drawing of the control defined by nPart
521  */
522 sal_Bool GtkSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart )
523 {
524     if (
525         ((nType==CTRL_PUSHBUTTON)  && (nPart==PART_ENTIRE_CONTROL))     ||
526         ((nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL))     ||
527         ((nType==CTRL_CHECKBOX)    && (nPart==PART_ENTIRE_CONTROL))     ||
528         ((nType==CTRL_SCROLLBAR) &&
529                 (  (nPart==PART_DRAW_BACKGROUND_HORZ)
530                 || (nPart==PART_DRAW_BACKGROUND_VERT)
531                 || (nPart==PART_ENTIRE_CONTROL)
532                 || (nPart==HAS_THREE_BUTTONS) )                 )   ||
533         ((nType==CTRL_EDITBOX) &&
534                 (  (nPart==PART_ENTIRE_CONTROL)
535                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
536         ((nType==CTRL_MULTILINE_EDITBOX) &&
537                 (  (nPart==PART_ENTIRE_CONTROL)
538                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
539         ((nType==CTRL_SPINBOX) &&
540                 (  (nPart==PART_ENTIRE_CONTROL)
541                 || (nPart==PART_ALL_BUTTONS)
542                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
543         ((nType==CTRL_SPINBUTTONS) &&
544                 (  (nPart==PART_ENTIRE_CONTROL)
545                 || (nPart==PART_ALL_BUTTONS)    )               )   ||
546         ((nType==CTRL_COMBOBOX) &&
547                 (  (nPart==PART_ENTIRE_CONTROL)
548                 || (nPart==HAS_BACKGROUND_TEXTURE)  )           )   ||
549         (((nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) ||
550           (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER)) &&
551                 (  (nPart==PART_ENTIRE_CONTROL)
552                 || (nPart==PART_TABS_DRAW_RTL) )                )   ||
553         ((nType==CTRL_LISTBOX) &&
554                 (  (nPart==PART_ENTIRE_CONTROL)
555                 || (nPart==PART_WINDOW)
556                 || (nPart==HAS_BACKGROUND_TEXTURE) )            )   ||
557         ((nType == CTRL_TOOLBAR) &&
558                 (   (nPart==PART_ENTIRE_CONTROL)
559                 ||  (nPart==PART_DRAW_BACKGROUND_HORZ)
560                 ||  (nPart==PART_DRAW_BACKGROUND_VERT)
561                 ||  (nPart==PART_THUMB_HORZ)
562                 ||  (nPart==PART_THUMB_VERT)
563                 ||  (nPart==PART_BUTTON)
564                 )
565                                                                 )   ||
566         ((nType == CTRL_MENUBAR) &&
567                 (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
568         ((nType == CTRL_TOOLTIP) &&
569                 (   (nPart==PART_ENTIRE_CONTROL) )              )   ||
570         ((nType == CTRL_MENU_POPUP) &&
571                 (   (nPart==PART_ENTIRE_CONTROL)
572                 ||  (nPart==PART_MENU_ITEM)
573                 ||  (nPart==PART_MENU_ITEM_CHECK_MARK)
574                 ||  (nPart==PART_MENU_ITEM_RADIO_MARK)
575                 )
576                                                                 )   ||
577         ((nType == CTRL_PROGRESS) &&
578                 (   (nPart == PART_ENTIRE_CONTROL) )
579                 )                                                   ||
580         ((nType == CTRL_LISTNODE || nType == CTRL_LISTNET) &&
581                 (   (nPart == PART_ENTIRE_CONTROL) )
582                 )                                                   ||
583         ((nType == CTRL_SLIDER) &&
584                 (   (nPart == PART_TRACK_HORZ_AREA)
585                 ||  (nPart == PART_TRACK_VERT_AREA)
586                 )
587         )
588         )
589         return( sal_True );
590 
591     return( sal_False );
592 }
593 
594 
595 /*
596  * HitTestNativeControl()
597  *
598  *  bIsInside is set to sal_True if aPos is contained within the
599  *  given part of the control, whose bounding region is
600  *  given by rControlRegion (in VCL frame coordinates).
601  *
602  *  returns whether bIsInside was really set.
603  */
604 sal_Bool GtkSalGraphics::hitTestNativeControl( ControlType      nType,
605                                 ControlPart     nPart,
606                                 const Rectangle&        rControlRegion,
607                                 const Point&        aPos,
608                                 sal_Bool&           rIsInside )
609 {
610     if ( ( nType == CTRL_SCROLLBAR ) &&
611          ( ( nPart == PART_BUTTON_UP ) ||
612            ( nPart == PART_BUTTON_DOWN ) ||
613            ( nPart == PART_BUTTON_LEFT ) ||
614            ( nPart == PART_BUTTON_RIGHT ) ) )
615     {
616         NWEnsureGTKScrollbars( m_nScreen );
617 
618         // Grab some button style attributes
619         gboolean has_forward;
620         gboolean has_forward2;
621         gboolean has_backward;
622         gboolean has_backward2;
623 
624         gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
625                                         "has-secondary-forward-stepper", &has_forward2,
626                                         "has-backward-stepper", &has_backward,
627                                         "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
628         Rectangle aForward;
629         Rectangle aBackward;
630 
631         rIsInside = sal_False;
632 
633         ControlPart nCounterPart = 0;
634         if ( nPart == PART_BUTTON_UP )
635             nCounterPart = PART_BUTTON_DOWN;
636         else if ( nPart == PART_BUTTON_DOWN )
637             nCounterPart = PART_BUTTON_UP;
638         else if ( nPart == PART_BUTTON_LEFT )
639             nCounterPart = PART_BUTTON_RIGHT;
640         else if ( nPart == PART_BUTTON_RIGHT )
641             nCounterPart = PART_BUTTON_LEFT;
642 
643         aBackward = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
644         aForward = NWGetScrollButtonRect( m_nScreen, nCounterPart, rControlRegion );
645 
646         if ( has_backward && has_forward2 )
647         {
648             Size aSize( aBackward.GetSize() );
649             if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
650                 aSize.setHeight( aBackward.GetHeight() / 2 );
651             else
652                 aSize.setWidth( aBackward.GetWidth() / 2 );
653             aBackward.SetSize( aSize );
654 
655             if ( nPart == PART_BUTTON_DOWN )
656                 aBackward.Move( 0, aBackward.GetHeight() / 2 );
657             else if ( nPart == PART_BUTTON_RIGHT )
658                 aBackward.Move( aBackward.GetWidth() / 2, 0 );
659         }
660 
661         if ( has_backward2 && has_forward )
662         {
663             Size aSize( aForward.GetSize() );
664             if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
665                 aSize.setHeight( aForward.GetHeight() / 2 );
666             else
667                 aSize.setWidth( aForward.GetWidth() / 2 );
668             aForward.SetSize( aSize );
669 
670             if ( nPart == PART_BUTTON_DOWN )
671                 aForward.Move( 0, aForward.GetHeight() / 2 );
672             else if ( nPart == PART_BUTTON_RIGHT )
673                 aForward.Move( aForward.GetWidth() / 2, 0 );
674         }
675 
676         if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_LEFT ) )
677         {
678             if ( has_backward )
679                 rIsInside |= aBackward.IsInside( aPos );
680             if ( has_backward2 )
681                 rIsInside |= aForward.IsInside( aPos );
682         }
683         else
684         {
685             if ( has_forward )
686                 rIsInside |= aBackward.IsInside( aPos );
687             if ( has_forward2 )
688                 rIsInside |= aForward.IsInside( aPos );
689         }
690         return ( sal_True );
691     }
692 
693     if( IsNativeControlSupported(nType, nPart) )
694     {
695         rIsInside = rControlRegion.IsInside( aPos );
696         return( sal_True );
697     }
698     else
699     {
700         return( sal_False );
701     }
702 }
703 
704 
705 /*
706  * DrawNativeControl()
707  *
708  *  Draws the requested control described by nPart/nState.
709  *
710  *  rControlRegion: The bounding region of the complete control in VCL frame coordinates.
711  *  aValue:         An optional value (tristate/numerical/string)
712  *  rCaption:   A caption or title string (like button text etc)
713  */
714 sal_Bool GtkSalGraphics::drawNativeControl( ControlType nType,
715                             ControlPart nPart,
716                             const Rectangle& rControlRegion,
717                             ControlState nState,
718                             const ImplControlValue& aValue,
719                             const OUString& rCaption )
720 {
721     sal_Bool            returnVal = sal_False;
722     // get a GC with current clipping region set
723     GetFontGC();
724 
725 
726     // theme changed ?
727     if( GtkSalGraphics::bThemeChanged )
728     {
729         // invalidate caches
730         for( unsigned int i = 0; i < gWidgetData.size(); i++ )
731             if( gWidgetData[i].gNWPixmapCacheList )
732                 gWidgetData[i].gNWPixmapCacheList->ThemeChanged();
733         GtkSalGraphics::bThemeChanged = sal_False;
734     }
735 
736     Rectangle aCtrlRect( rControlRegion );
737     Region aClipRegion( m_aClipRegion );
738     if( aClipRegion.IsNull() )
739         aClipRegion = aCtrlRect;
740 
741     clipList aClip;
742     GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() );
743     GdkPixmap* pixmap = NULL;
744     Rectangle aPixmapRect;
745     if( ( bNeedPixmapPaint )
746         && nType != CTRL_SCROLLBAR
747         && nType != CTRL_SPINBOX
748         && nType != CTRL_TAB_ITEM
749         && nType != CTRL_TAB_PANE
750         && nType != CTRL_PROGRESS
751         && ! (bToolbarGripWorkaround && nType == CTRL_TOOLBAR && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
752         )
753     {
754         // make pixmap a little larger since some themes draw decoration
755         // outside the rectangle, see e.g. checkbox
756         aPixmapRect = Rectangle( Point( aCtrlRect.Left()-1, aCtrlRect.Top()-1 ),
757                                  Size( aCtrlRect.GetWidth()+2, aCtrlRect.GetHeight()+2) );
758         pixmap = NWGetPixmapFromScreen( aPixmapRect );
759         if( ! pixmap )
760             return sal_False;
761         gdkDrawable = GDK_DRAWABLE( pixmap );
762         aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() );
763         aClip.push_back( aCtrlRect );
764     }
765     else
766     {
767         RegionHandle aHdl = aClipRegion.BeginEnumRects();
768         Rectangle aPaintRect;
769         while( aClipRegion.GetNextEnumRect( aHdl, aPaintRect ) )
770         {
771             aPaintRect = aCtrlRect.GetIntersection( aPaintRect );
772             if( aPaintRect.IsEmpty() )
773                 continue;
774             aClip.push_back( aPaintRect );
775         }
776         aClipRegion.EndEnumRects( aHdl );
777     }
778 
779     if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
780     {
781         returnVal = NWPaintGTKButton( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
782     }
783     else if ( (nType==CTRL_RADIOBUTTON) && (nPart==PART_ENTIRE_CONTROL) )
784     {
785         returnVal = NWPaintGTKRadio( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
786     }
787     else if ( (nType==CTRL_CHECKBOX) && (nPart==PART_ENTIRE_CONTROL) )
788     {
789         returnVal = NWPaintGTKCheck( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
790     }
791     else if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_DRAW_BACKGROUND_HORZ) || (nPart==PART_DRAW_BACKGROUND_VERT)) )
792     {
793         returnVal = NWPaintGTKScrollbar( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
794     }
795     else if ( ((nType==CTRL_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) )
796         || ((nType==CTRL_SPINBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
797     || ((nType==CTRL_COMBOBOX) && (nPart==HAS_BACKGROUND_TEXTURE))
798     || ((nType==CTRL_LISTBOX) && (nPart==HAS_BACKGROUND_TEXTURE)) )
799     {
800         returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
801     }
802     else if ( ((nType==CTRL_MULTILINE_EDITBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==HAS_BACKGROUND_TEXTURE)) ) )
803     {
804         returnVal = NWPaintGTKEditBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
805     }
806     else if ( ((nType==CTRL_SPINBOX) || (nType==CTRL_SPINBUTTONS))
807         && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_ALL_BUTTONS)) )
808     {
809         returnVal = NWPaintGTKSpinBox( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
810     }
811     else if ( (nType == CTRL_COMBOBOX) &&
812         ( (nPart==PART_ENTIRE_CONTROL)
813         ||(nPart==PART_BUTTON_DOWN)
814         ) )
815     {
816         returnVal = NWPaintGTKComboBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
817     }
818     else if ( (nType==CTRL_TAB_ITEM) || (nType==CTRL_TAB_PANE) || (nType==CTRL_TAB_BODY) || (nType==CTRL_FIXEDBORDER) )
819     {
820         if ( nType == CTRL_TAB_BODY )
821             returnVal = sal_True;
822         else
823             returnVal = NWPaintGTKTabItem( nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption);
824     }
825     else if ( (nType==CTRL_LISTBOX) && ((nPart==PART_ENTIRE_CONTROL) || (nPart==PART_WINDOW)) )
826     {
827         returnVal = NWPaintGTKListBox( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
828     }
829     else if ( (nType== CTRL_TOOLBAR) )
830     {
831         returnVal = NWPaintGTKToolbar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
832     }
833     else if ( (nType== CTRL_MENUBAR) )
834     {
835         returnVal = NWPaintGTKMenubar( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
836     }
837     else if(    (nType == CTRL_MENU_POPUP)
838         && (  (nPart == PART_ENTIRE_CONTROL)
839     || (nPart == PART_MENU_ITEM)
840     || (nPart == PART_MENU_ITEM_CHECK_MARK)
841     || (nPart == PART_MENU_ITEM_RADIO_MARK)
842     )
843     )
844     {
845         returnVal = NWPaintGTKPopupMenu( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
846     }
847     else if( (nType == CTRL_TOOLTIP) && (nPart == PART_ENTIRE_CONTROL) )
848     {
849         returnVal = NWPaintGTKTooltip( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
850     }
851     else if( (nType == CTRL_PROGRESS) && (nPart == PART_ENTIRE_CONTROL) )
852     {
853         returnVal = NWPaintGTKProgress( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
854     }
855     else if( (nType == CTRL_LISTNODE) && (nPart == PART_ENTIRE_CONTROL) )
856     {
857         returnVal = NWPaintGTKListNode( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
858     }
859     else if( (nType == CTRL_LISTNET) && (nPart == PART_ENTIRE_CONTROL) )
860     {
861         // don't actually draw anything; gtk treeviews do not draw lines
862         returnVal = true;
863     }
864     else if( (nType == CTRL_SLIDER) )
865     {
866         returnVal = NWPaintGTKSlider( gdkDrawable, nType, nPart, aCtrlRect, aClip, nState, aValue, rCaption );
867     }
868 
869     if( pixmap )
870     {
871         returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal;
872         g_object_unref( pixmap );
873     }
874 
875     return( returnVal );
876 }
877 
878 /*
879  * DrawNativeControlText()
880  *
881  *  OPTIONAL.  Draws the requested text for the control described by nPart/nState.
882  *     Used if text not drawn by DrawNativeControl().
883  *
884  *  rControlRegion: The bounding region of the complete control in VCL frame coordinates.
885  *  aValue:         An optional value (tristate/numerical/string)
886  *  rCaption:   A caption or title string (like button text etc)
887  */
888 sal_Bool GtkSalGraphics::drawNativeControlText( ControlType,
889                                 ControlPart,
890                                 const Rectangle&,
891                                 ControlState,
892                                 const ImplControlValue&,
893                                 const OUString& )
894 {
895     return( sal_False );
896 }
897 
898 
899 /*
900  * GetNativeControlRegion()
901  *
902  *  If the return value is sal_True, rNativeBoundingRegion
903  *  contains the true bounding region covered by the control
904  *  including any adornment, while rNativeContentRegion contains the area
905  *  within the control that can be safely drawn into without drawing over
906  *  the borders of the control.
907  *
908  *  rControlRegion: The bounding region of the control in VCL frame coordinates.
909  *  aValue:     An optional value (tristate/numerical/string)
910  *  rCaption:       A caption or title string (like button text etc)
911  */
912 sal_Bool GtkSalGraphics::getNativeControlRegion(  ControlType nType,
913                                 ControlPart nPart,
914                                 const Rectangle& rControlRegion,
915                                 ControlState nState,
916                                 const ImplControlValue& aValue,
917                                 const OUString& rCaption,
918                                 Rectangle &rNativeBoundingRegion,
919                                 Rectangle &rNativeContentRegion )
920 {
921     sal_Bool returnVal = sal_False;
922 
923     if ( (nType==CTRL_PUSHBUTTON) && (nPart==PART_ENTIRE_CONTROL)
924         && (rControlRegion.GetWidth() > 16)
925     && (rControlRegion.GetHeight() > 16) )
926     {
927         rNativeBoundingRegion = NWGetButtonArea( m_nScreen, nType, nPart, rControlRegion,
928         nState, aValue, rCaption );
929         rNativeContentRegion = rControlRegion;
930 
931         returnVal = sal_True;
932     }
933     if ( (nType==CTRL_COMBOBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
934     {
935         rNativeBoundingRegion = NWGetComboBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
936         aValue, rCaption );
937         rNativeContentRegion = rNativeBoundingRegion;
938 
939         returnVal = sal_True;
940     }
941     if ( (nType==CTRL_SPINBOX) && ((nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
942     {
943 
944         rNativeBoundingRegion = NWGetSpinButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
945         aValue, rCaption );
946         rNativeContentRegion = rNativeBoundingRegion;
947 
948         returnVal = sal_True;
949     }
950     if ( (nType==CTRL_LISTBOX) && ((nPart==PART_BUTTON_DOWN) || (nPart==PART_SUB_EDIT)) )
951     {
952         rNativeBoundingRegion = NWGetListBoxButtonRect( m_nScreen, nType, nPart, rControlRegion, nState,
953         aValue, rCaption );
954         rNativeContentRegion = rNativeBoundingRegion;
955 
956         returnVal = sal_True;
957     }
958     if ( (nType==CTRL_TOOLBAR) &&
959         ((nPart==PART_DRAW_BACKGROUND_HORZ) ||
960         (nPart==PART_DRAW_BACKGROUND_VERT)  ||
961         (nPart==PART_THUMB_HORZ)            ||
962         (nPart==PART_THUMB_VERT)            ||
963         (nPart==PART_BUTTON)
964         ))
965     {
966         rNativeBoundingRegion = NWGetToolbarRect( m_nScreen, nType, nPart, rControlRegion, nState, aValue, rCaption );
967         rNativeContentRegion = rNativeBoundingRegion;
968         returnVal = sal_True;
969     }
970     if ( (nType==CTRL_SCROLLBAR) && ((nPart==PART_BUTTON_LEFT) || (nPart==PART_BUTTON_RIGHT) ||
971         (nPart==PART_BUTTON_UP) || (nPart==PART_BUTTON_DOWN)  ) )
972     {
973         rNativeBoundingRegion = NWGetScrollButtonRect( m_nScreen, nPart, rControlRegion );
974         rNativeContentRegion = rNativeBoundingRegion;
975 
976         returnVal = sal_True;
977     }
978     if( (nType == CTRL_MENUBAR) && (nPart == PART_ENTIRE_CONTROL) )
979     {
980         NWEnsureGTKMenubar( m_nScreen );
981         GtkRequisition aReq;
982         gtk_widget_size_request( gWidgetData[m_nScreen].gMenubarWidget, &aReq );
983         Rectangle aMenuBarRect = rControlRegion;
984         aMenuBarRect = Rectangle( aMenuBarRect.TopLeft(),
985                                   Size( aMenuBarRect.GetWidth(), aReq.height+1 ) );
986         rNativeBoundingRegion = aMenuBarRect;
987         rNativeContentRegion = rNativeBoundingRegion;
988         returnVal = sal_True;
989     }
990     if( (nType == CTRL_MENU_POPUP) )
991     {
992         if( (nPart == PART_MENU_ITEM_CHECK_MARK) ||
993             (nPart == PART_MENU_ITEM_RADIO_MARK) )
994         {
995             NWEnsureGTKMenu( m_nScreen );
996 
997             gint indicator_size = 0;
998             GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
999                                  gWidgetData[m_nScreen].gMenuItemCheckMenuWidget : gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
1000             gtk_widget_style_get( pWidget,
1001                                   "indicator_size", &indicator_size,
1002                                   (char *)NULL );
1003             rNativeBoundingRegion = rControlRegion;
1004             Rectangle aIndicatorRect( Point( 0,
1005                                              (rControlRegion.GetHeight()-indicator_size)/2),
1006                                       Size( indicator_size, indicator_size ) );
1007             rNativeContentRegion = aIndicatorRect;
1008             returnVal = sal_True;
1009         }
1010     }
1011     if( (nType == CTRL_RADIOBUTTON || nType == CTRL_CHECKBOX) )
1012     {
1013         NWEnsureGTKRadio( m_nScreen );
1014         NWEnsureGTKCheck( m_nScreen );
1015         GtkWidget* widget = (nType == CTRL_RADIOBUTTON) ? gWidgetData[m_nScreen].gRadioWidget : gWidgetData[m_nScreen].gCheckWidget;
1016         gint indicator_size, indicator_spacing;
1017         gtk_widget_style_get( widget,
1018                               "indicator_size", &indicator_size,
1019                               "indicator_spacing", &indicator_spacing,
1020                               (char *)NULL);
1021         indicator_size += 2*indicator_spacing; // guess overpaint of theme
1022         rNativeBoundingRegion = rControlRegion;
1023         Rectangle aIndicatorRect( Point( 0,
1024                                          (rControlRegion.GetHeight()-indicator_size)/2),
1025                                   Size( indicator_size, indicator_size ) );
1026         rNativeContentRegion = aIndicatorRect;
1027         returnVal = sal_True;
1028     }
1029     if( (nType == CTRL_EDITBOX || nType == CTRL_SPINBOX) && nPart == PART_ENTIRE_CONTROL )
1030     {
1031         NWEnsureGTKEditBox( m_nScreen );
1032         GtkWidget* widget = gWidgetData[m_nScreen].gEditBoxWidget;
1033         GtkRequisition aReq;
1034         gtk_widget_size_request( widget, &aReq );
1035         Rectangle aEditRect = rControlRegion;
1036         long nHeight = (aEditRect.GetHeight() > aReq.height+1) ? aEditRect.GetHeight() : aReq.height+1;
1037         aEditRect = Rectangle( aEditRect.TopLeft(),
1038                                Size( aEditRect.GetWidth(), nHeight ) );
1039         rNativeBoundingRegion = aEditRect;
1040         rNativeContentRegion = rNativeBoundingRegion;
1041         returnVal = sal_True;
1042     }
1043     if( (nType == CTRL_SLIDER) && (nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT) )
1044     {
1045         NWEnsureGTKSlider( m_nScreen );
1046         GtkWidget* widget = (nPart == PART_THUMB_HORZ) ? gWidgetData[m_nScreen].gHScale : gWidgetData[m_nScreen].gVScale;
1047         gint slider_length = 10;
1048         gint slider_width = 10;
1049         gtk_widget_style_get( widget,
1050                               "slider-width", &slider_width,
1051                               "slider-length", &slider_length,
1052                               (char *)NULL);
1053         Rectangle aRect( rControlRegion );
1054         if( nPart == PART_THUMB_HORZ )
1055         {
1056             aRect.Right() = aRect.Left() + slider_length - 1;
1057             aRect.Bottom() = aRect.Top() + slider_width - 1;
1058         }
1059         else
1060         {
1061             aRect.Bottom() = aRect.Top() + slider_length - 1;
1062             aRect.Right() = aRect.Left() + slider_width - 1;
1063         }
1064         rNativeBoundingRegion = rNativeContentRegion = aRect;
1065         returnVal = sal_True;
1066     }
1067 
1068     return( returnVal );
1069 }
1070 
1071 
1072 /************************************************************************
1073  * Individual control drawing functions
1074  ************************************************************************/
1075 sal_Bool GtkSalGraphics::NWPaintGTKButton(
1076             GdkDrawable* gdkDrawable,
1077             ControlType, ControlPart,
1078             const Rectangle& rControlRectangle,
1079             const clipList& rClipList,
1080             ControlState nState, const ImplControlValue&,
1081             const OUString& )
1082 {
1083     GtkStateType    stateType;
1084     GtkShadowType   shadowType;
1085     gboolean        interiorFocus;
1086     gint            focusWidth;
1087     gint            focusPad;
1088     sal_Bool            bDrawFocus = sal_True;
1089     gint            x, y, w, h;
1090     GtkBorder       aDefBorder;
1091     GtkBorder*      pBorder;
1092     GdkRectangle    clipRect;
1093 
1094     NWEnsureGTKButton( m_nScreen );
1095     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1096 
1097     x = rControlRectangle.Left();
1098     y = rControlRectangle.Top();
1099     w = rControlRectangle.GetWidth();
1100     h = rControlRectangle.GetHeight();
1101 
1102     // Grab some button style attributes
1103     gtk_widget_style_get( gWidgetData[m_nScreen].gBtnWidget,    "focus-line-width", &focusWidth,
1104                                 "focus-padding",    &focusPad,
1105                                 "interior_focus",   &interiorFocus,
1106                                 "default_border",   &pBorder,
1107                                 (char *)NULL );
1108 
1109     // Make sure the border values exist, otherwise use some defaults
1110     if ( pBorder )
1111     {
1112         NW_gtk_border_set_from_border( aDefBorder, pBorder );
1113         gtk_border_free( pBorder );
1114     }
1115     else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1116 
1117     // If the button is too small, don't ever draw focus or grab more space
1118     if ( (w < 16) || (h < 16) )
1119         bDrawFocus = sal_False;
1120 
1121     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
1122 
1123     gint xi = x, yi = y, wi = w, hi = h;
1124     if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
1125     {
1126         xi += aDefBorder.left;
1127         yi += aDefBorder.top;
1128         wi -= aDefBorder.left + aDefBorder.right;
1129         hi -= aDefBorder.top + aDefBorder.bottom;
1130     }
1131 
1132     if ( !interiorFocus && bDrawFocus )
1133     {
1134         xi += focusWidth + focusPad;
1135         yi += focusWidth + focusPad;
1136         wi -= 2 * (focusWidth + focusPad);
1137         hi -= 2 * (focusWidth + focusPad);
1138     }
1139 
1140     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it)
1141     {
1142         clipRect.x = it->Left();
1143         clipRect.y = it->Top();
1144         clipRect.width = it->GetWidth();
1145         clipRect.height = it->GetHeight();
1146 
1147         // Buttons must paint opaque since some themes have alpha-channel enabled buttons
1148         gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
1149                             &clipRect, m_pWindow, "base", x, y, w, h );
1150 
1151         if ( (nState & CTRL_STATE_DEFAULT) && (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief == GTK_RELIEF_NORMAL) )
1152         {
1153             gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1154                            &clipRect, gWidgetData[m_nScreen].gBtnWidget, "buttondefault", x, y, w, h );
1155         }
1156 
1157         if ( (GTK_BUTTON(gWidgetData[m_nScreen].gBtnWidget)->relief != GTK_RELIEF_NONE)
1158             || (nState & CTRL_STATE_PRESSED)
1159             || (nState & CTRL_STATE_ROLLOVER) )
1160         {
1161             gtk_paint_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, shadowType,
1162                            &clipRect, gWidgetData[m_nScreen].gBtnWidget, "button", xi, yi, wi, hi );
1163         }
1164     }
1165 #if 0 // VCL draws focus rects
1166     // Draw focus rect
1167     if ( (nState & CTRL_STATE_FOCUSED) && (nState & CTRL_STATE_ENABLED) && bDrawFocus )
1168     {
1169         if (interiorFocus)
1170         {
1171             x += gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad;
1172             y += gWidgetData[m_nScreen].gBtnWidget->style->ythickness + focusPad;
1173             w -= 2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
1174             h -=  2 * (gWidgetData[m_nScreen].gBtnWidget->style->xthickness + focusPad);
1175         }
1176         else
1177         {
1178             x -= focusWidth + focusPad;
1179             y -= focusWidth + focusPad;
1180             w += 2 * (focusWidth + focusPad);
1181             h += 2 * (focusWidth + focusPad);
1182         }
1183         if ( !interiorFocus )
1184             gtk_paint_focus( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, stateType, &clipRect,
1185                              gWidgetData[m_nScreen].gBtnWidget, "button", x, y, w, h );
1186     }
1187 #endif
1188 
1189     return( sal_True );
1190 }
1191 
1192 static Rectangle NWGetButtonArea( int nScreen,
1193                                   ControlType, ControlPart, Rectangle aAreaRect, ControlState nState,
1194                                   const ImplControlValue&, const OUString& )
1195 {
1196     gboolean        interiorFocus;
1197     gint            focusWidth;
1198     gint            focusPad;
1199     GtkBorder       aDefBorder;
1200     GtkBorder * pBorder;
1201     sal_Bool            bDrawFocus = sal_True;
1202     Rectangle       aRect;
1203     gint            x, y, w, h;
1204 
1205     NWEnsureGTKButton( nScreen );
1206     gtk_widget_style_get( gWidgetData[nScreen].gBtnWidget,
1207                                 "focus-line-width", &focusWidth,
1208                                 "focus-padding",    &focusPad,
1209                                 "interior_focus",   &interiorFocus,
1210                                 "default_border",   &pBorder,
1211                                 (char *)NULL );
1212 
1213     // Make sure the border values exist, otherwise use some defaults
1214     if ( pBorder )
1215     {
1216         NW_gtk_border_set_from_border( aDefBorder, pBorder );
1217         gtk_border_free( pBorder );
1218     }
1219     else NW_gtk_border_set_from_border( aDefBorder, &aDefDefBorder );
1220 
1221     x = aAreaRect.Left();
1222     y = aAreaRect.Top();
1223     w = aAreaRect.GetWidth();
1224     h = aAreaRect.GetHeight();
1225 
1226     // If the button is too small, don't ever draw focus or grab more space
1227     if ( (w < 16) || (h < 16) )
1228         bDrawFocus = sal_False;
1229 
1230     if ( (nState & CTRL_STATE_DEFAULT) && bDrawFocus )
1231     {
1232         x -= aDefBorder.left;
1233         y -= aDefBorder.top;
1234         w += aDefBorder.left + aDefBorder.right;
1235         h += aDefBorder.top + aDefBorder.bottom;
1236     }
1237 
1238     aRect = Rectangle( Point( x, y ), Size( w, h ) );
1239 
1240     return( aRect );
1241 }
1242 
1243 //-------------------------------------
1244 
1245 sal_Bool GtkSalGraphics::NWPaintGTKRadio( GdkDrawable* gdkDrawable,
1246                                       ControlType, ControlPart,
1247                                       const Rectangle& rControlRectangle,
1248                                       const clipList& rClipList,
1249                                       ControlState nState,
1250                                       const ImplControlValue& aValue,
1251                                       const OUString& )
1252 {
1253     GtkStateType    stateType;
1254     GtkShadowType   shadowType;
1255     sal_Bool            isChecked = (aValue.getTristateVal()==BUTTONVALUE_ON);
1256     gint            x, y;
1257     GdkRectangle    clipRect;
1258 
1259     NWEnsureGTKButton( m_nScreen );
1260     NWEnsureGTKRadio( m_nScreen );
1261     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1262 
1263     gint indicator_size;
1264     gtk_widget_style_get( gWidgetData[m_nScreen].gRadioWidget, "indicator_size", &indicator_size, (char *)NULL);
1265 
1266     x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1267     y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1268 
1269     // Set the shadow based on if checked or not so we get a freakin checkmark.
1270     shadowType = isChecked ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1271     NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidget, nState, stateType );
1272     NWSetWidgetState( gWidgetData[m_nScreen].gRadioWidgetSibling, nState, stateType );
1273 
1274     // GTK enforces radio groups, so that if we don't have 2 buttons in the group,
1275     // the single button will always be active.  So we have to have 2 buttons.
1276 
1277     // #i59666# set the members directly where we should use
1278     // gtk_toggle_button_set_active. reason: there are animated themes
1279     // which are in active state only after a while leading to painting
1280     // intermediate states between active/inactive. Let's hope that
1281     // GtkToggleButtone stays binary compatible.
1282     if (!isChecked)
1283         GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidgetSibling)->active = sal_True;
1284     GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gRadioWidget)->active = isChecked;
1285 
1286     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1287     {
1288         clipRect.x = it->Left();
1289         clipRect.y = it->Top();
1290         clipRect.width = it->GetWidth();
1291         clipRect.height = it->GetHeight();
1292 
1293         gtk_paint_option( gWidgetData[m_nScreen].gRadioWidget->style, gdkDrawable, stateType, shadowType,
1294                           &clipRect, gWidgetData[m_nScreen].gRadioWidget, "radiobutton",
1295                           x, y, indicator_size, indicator_size );
1296     }
1297 
1298     return( sal_True );
1299 }
1300 
1301 //-------------------------------------
1302 
1303 sal_Bool GtkSalGraphics::NWPaintGTKCheck( GdkDrawable* gdkDrawable,
1304                                       ControlType, ControlPart,
1305                                       const Rectangle& rControlRectangle,
1306                                       const clipList& rClipList,
1307                                       ControlState nState,
1308                                       const ImplControlValue& aValue,
1309                                       const OUString& )
1310 {
1311     GtkStateType    stateType;
1312     GtkShadowType   shadowType;
1313     bool            isChecked = (aValue.getTristateVal() == BUTTONVALUE_ON);
1314     bool            isInconsistent = (aValue.getTristateVal() == BUTTONVALUE_MIXED);
1315     GdkRectangle    clipRect;
1316     gint            x,y;
1317 
1318     NWEnsureGTKButton( m_nScreen );
1319     NWEnsureGTKCheck( m_nScreen );
1320     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1321 
1322     gint indicator_size;
1323     gtk_widget_style_get( gWidgetData[m_nScreen].gCheckWidget, "indicator_size", &indicator_size, (char *)NULL);
1324 
1325     x = rControlRectangle.Left() + (rControlRectangle.GetWidth()-indicator_size)/2;
1326     y = rControlRectangle.Top() + (rControlRectangle.GetHeight()-indicator_size)/2;
1327 
1328     // Set the shadow based on if checked or not so we get a checkmark.
1329     shadowType = isChecked ? GTK_SHADOW_IN : isInconsistent ? GTK_SHADOW_ETCHED_IN : GTK_SHADOW_OUT;
1330     NWSetWidgetState( gWidgetData[m_nScreen].gCheckWidget, nState, stateType );
1331     GTK_TOGGLE_BUTTON(gWidgetData[m_nScreen].gCheckWidget)->active = isChecked;
1332 
1333     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1334     {
1335         clipRect.x = it->Left();
1336         clipRect.y = it->Top();
1337         clipRect.width = it->GetWidth();
1338         clipRect.height = it->GetHeight();
1339 
1340         gtk_paint_check( gWidgetData[m_nScreen].gCheckWidget->style, gdkDrawable, stateType, shadowType,
1341                          &clipRect, gWidgetData[m_nScreen].gCheckWidget, "checkbutton",
1342                          x, y, indicator_size, indicator_size );
1343     }
1344 
1345     return( sal_True );
1346 }
1347 
1348 //-------------------------------------
1349 static void NWCalcArrowRect( const Rectangle& rButton, Rectangle& rArrow )
1350 {
1351     // Size the arrow appropriately
1352     Size aSize( rButton.GetWidth()/2, rButton.GetHeight()/2 );
1353     rArrow.SetSize( aSize );
1354 
1355     rArrow.SetPos( Point(
1356         rButton.Left() + ( rButton.GetWidth()  - rArrow.GetWidth()  ) / 2,
1357         rButton.Top() + ( rButton.GetHeight() - rArrow.GetHeight() ) / 2
1358         ) );
1359 }
1360 
1361 sal_Bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart,
1362                                           const Rectangle& rControlRectangle,
1363                                           const clipList&,
1364                                           ControlState nState,
1365                                           const ImplControlValue& aValue,
1366                                           const OUString& )
1367 {
1368     OSL_ASSERT( aValue.getType() == CTRL_SCROLLBAR );
1369     const ScrollbarValue* pScrollbarVal = static_cast<const ScrollbarValue *>(&aValue);
1370     GdkPixmap*      pixmap = NULL;
1371     Rectangle       pixmapRect, scrollbarRect;
1372     GtkStateType    stateType;
1373     GtkShadowType   shadowType;
1374     GtkScrollbar *  scrollbarWidget;
1375     GtkStyle *  style;
1376     GtkAdjustment* scrollbarValues = NULL;
1377     GtkOrientation  scrollbarOrientation;
1378     Rectangle       thumbRect = pScrollbarVal->maThumbRect;
1379     Rectangle       button11BoundRect = pScrollbarVal->maButton1Rect;   // backward
1380     Rectangle       button22BoundRect = pScrollbarVal->maButton2Rect;   // forward
1381     Rectangle       button12BoundRect = pScrollbarVal->maButton1Rect;   // secondary forward
1382     Rectangle       button21BoundRect = pScrollbarVal->maButton2Rect;   // secondary backward
1383     GtkArrowType    button1Type;                                        // backward
1384     GtkArrowType    button2Type;                                        // forward
1385     gchar *     scrollbarTagH = (gchar *) "hscrollbar";
1386     gchar *     scrollbarTagV = (gchar *) "vscrollbar";
1387     gchar *     scrollbarTag = NULL;
1388     Rectangle       arrowRect;
1389     gint            slider_width = 0;
1390     gint            stepper_size = 0;
1391     gint            stepper_spacing = 0;
1392     gint            trough_border = 0;
1393     gint            min_slider_length = 0;
1394     gint            vShim = 0;
1395     gint            hShim = 0;
1396     gint            x,y,w,h;
1397 
1398     // make controlvalue rectangles relative to area
1399     thumbRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1400     button11BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1401     button22BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1402     button12BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1403     button21BoundRect.Move( -rControlRectangle.Left(), -rControlRectangle.Top() );
1404 
1405     NWEnsureGTKButton( m_nScreen );
1406     NWEnsureGTKScrollbars( m_nScreen );
1407     NWEnsureGTKArrow( m_nScreen );
1408 
1409     // Find the overall bounding rect of the control
1410     pixmapRect = rControlRectangle;
1411     pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 1,
1412                               pixmapRect.GetHeight() + 1 ) );
1413     scrollbarRect = pixmapRect;
1414 
1415     if ( (scrollbarRect.GetWidth() <= 1) || (scrollbarRect.GetHeight() <= 1) )
1416         return( sal_True );
1417 
1418     // Grab some button style attributes
1419     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
1420                                       "slider_width", &slider_width,
1421                                       "stepper_size", &stepper_size,
1422                                       "trough_border", &trough_border,
1423                                       "stepper_spacing", &stepper_spacing,
1424                                       "min_slider_length", &min_slider_length, (char *)NULL );
1425     gboolean has_forward;
1426     gboolean has_forward2;
1427     gboolean has_backward;
1428     gboolean has_backward2;
1429 
1430     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget, "has-forward-stepper", &has_forward,
1431                                       "has-secondary-forward-stepper", &has_forward2,
1432                                       "has-backward-stepper", &has_backward,
1433                                       "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
1434     gint magic = trough_border ? 1 : 0;
1435     gint nFirst = 0;
1436 
1437     if ( has_backward )  nFirst  += 1;
1438     if ( has_forward2 )  nFirst  += 1;
1439 
1440     if ( nPart == PART_DRAW_BACKGROUND_HORZ )
1441     {
1442         unsigned int sliderHeight = slider_width + (trough_border * 2);
1443         vShim = (pixmapRect.GetHeight() - sliderHeight) / 2;
1444 
1445         scrollbarRect.Move( 0, vShim );
1446         scrollbarRect.SetSize( Size( scrollbarRect.GetWidth(), sliderHeight ) );
1447 
1448         scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollHorizWidget );
1449         scrollbarOrientation = GTK_ORIENTATION_HORIZONTAL;
1450         scrollbarTag = scrollbarTagH;
1451         button1Type = GTK_ARROW_LEFT;
1452         button2Type = GTK_ARROW_RIGHT;
1453 
1454         if ( has_backward )
1455         {
1456             button12BoundRect.Move( stepper_size - trough_border,
1457                                     (scrollbarRect.GetHeight() - slider_width) / 2 );
1458         }
1459 
1460         button11BoundRect.Move( trough_border, (scrollbarRect.GetHeight() - slider_width) / 2 );
1461         button11BoundRect.SetSize( Size( stepper_size, slider_width ) );
1462         button12BoundRect.SetSize( Size( stepper_size, slider_width ) );
1463 
1464         if ( has_backward2 )
1465         {
1466             button22BoundRect.Move( stepper_size+(trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1467             button21BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1468         }
1469         else
1470         {
1471             button22BoundRect.Move( (trough_border+1)/2, (scrollbarRect.GetHeight() - slider_width) / 2 );
1472         }
1473 
1474         button21BoundRect.SetSize( Size( stepper_size, slider_width ) );
1475         button22BoundRect.SetSize( Size( stepper_size, slider_width ) );
1476 
1477         thumbRect.Bottom() = thumbRect.Top() + slider_width - 1;
1478         // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
1479         // but if the VCL gives us a size smaller than the theme's default thumb size,
1480         // honor the VCL size
1481 #if 0
1482         if ( (thumbRect.GetWidth() < min_slider_length)
1483             && ((scrollbarRect.GetWidth()-button1BoundRect.GetWidth()-button2BoundRect.GetWidth()) > min_slider_length) )
1484             thumbRect.SetSize( Size( min_slider_length, thumbRect.GetHeight() ) );
1485 #endif
1486 
1487         thumbRect.Right() += magic;
1488         // Center vertically in the track
1489         thumbRect.Move( 0, (scrollbarRect.GetHeight() - slider_width) / 2 );
1490     }
1491     else
1492     {
1493         unsigned int sliderWidth = slider_width + (trough_border * 2);
1494         hShim = (pixmapRect.GetWidth() - sliderWidth) / 2;
1495 
1496         scrollbarRect.Move( hShim, 0 );
1497         scrollbarRect.SetSize( Size( sliderWidth, scrollbarRect.GetHeight() ) );
1498 
1499         scrollbarWidget = GTK_SCROLLBAR( gWidgetData[m_nScreen].gScrollVertWidget );
1500         scrollbarOrientation = GTK_ORIENTATION_VERTICAL;
1501         scrollbarTag = scrollbarTagV;
1502         button1Type = GTK_ARROW_UP;
1503         button2Type = GTK_ARROW_DOWN;
1504 
1505         if ( has_backward )
1506         {
1507             button12BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2,
1508                                     stepper_size + trough_border );
1509         }
1510         button11BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, trough_border );
1511         button11BoundRect.SetSize( Size( slider_width, stepper_size ) );
1512         button12BoundRect.SetSize( Size( slider_width, stepper_size ) );
1513 
1514         if ( has_backward2 )
1515         {
1516             button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, stepper_size+(trough_border+1)/2 );
1517             button21BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
1518         }
1519         else
1520         {
1521             button22BoundRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, (trough_border+1)/2 );
1522         }
1523 
1524         button21BoundRect.SetSize( Size( slider_width, stepper_size ) );
1525         button22BoundRect.SetSize( Size( slider_width, stepper_size ) );
1526 
1527         thumbRect.Right() = thumbRect.Left() + slider_width - 1;
1528 #if 0
1529         // Make sure the thumb is at least the default width (so we don't get tiny thumbs),
1530         // but if the VCL gives us a size smaller than the theme's default thumb size,
1531         // honor the VCL size
1532         if ( (thumbRect.GetHeight() < min_slider_length)
1533             && ((scrollbarRect.GetHeight()-button1BoundRect.GetHeight()-button2BoundRect.GetHeight()) > min_slider_length) )
1534             thumbRect.SetSize( Size( thumbRect.GetWidth(), min_slider_length ) );
1535 #endif
1536 
1537         thumbRect.Bottom() += magic;
1538         // Center horizontally in the track
1539         thumbRect.Move( (scrollbarRect.GetWidth() - slider_width) / 2, 0 );
1540     }
1541 
1542     sal_Bool has_slider = ( thumbRect.GetWidth() > 0 && thumbRect.GetHeight() > 0 );
1543 
1544     scrollbarValues = gtk_range_get_adjustment( GTK_RANGE(scrollbarWidget) );
1545     if ( scrollbarValues == NULL )
1546         scrollbarValues = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
1547     if ( nPart == PART_DRAW_BACKGROUND_HORZ )
1548     {
1549         scrollbarValues->lower = pScrollbarVal->mnMin;
1550         scrollbarValues->upper = pScrollbarVal->mnMax;
1551         scrollbarValues->value = pScrollbarVal->mnCur;
1552         scrollbarValues->page_size = scrollbarRect.GetWidth() / 2;
1553     }
1554     else
1555     {
1556         scrollbarValues->lower = pScrollbarVal->mnMin;
1557         scrollbarValues->upper = pScrollbarVal->mnMax;
1558         scrollbarValues->value = pScrollbarVal->mnCur;
1559         scrollbarValues->page_size = scrollbarRect.GetHeight() / 2;
1560     }
1561     gtk_adjustment_changed( scrollbarValues );
1562 
1563     // as multiple paints are required for the scrollbar
1564     // painting them directly to the window flickers
1565     pixmap = NWGetPixmapFromScreen( pixmapRect );
1566     if( ! pixmap )
1567         return sal_False;
1568     x = y = 0;
1569 
1570     w = pixmapRect.GetWidth();
1571     h = pixmapRect.GetHeight();
1572 
1573     GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap );
1574     GdkRectangle* gdkRect = NULL;
1575 
1576     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1577     NWSetWidgetState( GTK_WIDGET(scrollbarWidget), nState, stateType );
1578     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
1579     style = GTK_WIDGET( scrollbarWidget )->style;
1580 
1581     // ----------------- TROUGH
1582     gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable,
1583                         GTK_STATE_NORMAL, GTK_SHADOW_NONE, gdkRect,
1584                         m_pWindow, "base", x, y,
1585                         w, h );
1586     gtk_paint_box( style, gdkDrawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN,
1587                    gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
1588                    x, y,
1589                    scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
1590 
1591     if ( nState & CTRL_STATE_FOCUSED )
1592     {
1593         gtk_paint_focus( style, gdkDrawable, GTK_STATE_ACTIVE,
1594                          gdkRect, GTK_WIDGET(scrollbarWidget), "trough",
1595                          x, y,
1596                          scrollbarRect.GetWidth(), scrollbarRect.GetHeight() );
1597     }
1598 
1599     // ----------------- THUMB
1600     if ( has_slider )
1601     {
1602         NWConvertVCLStateToGTKState( pScrollbarVal->mnThumbState, &stateType, &shadowType );
1603         if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )  stateType = GTK_STATE_PRELIGHT;
1604         gtk_paint_slider( style, gdkDrawable, stateType, GTK_SHADOW_OUT,
1605                         gdkRect, GTK_WIDGET(scrollbarWidget), "slider",
1606                         x+hShim+thumbRect.Left(), y+vShim+thumbRect.Top(),
1607                         thumbRect.GetWidth(), thumbRect.GetHeight(), scrollbarOrientation );
1608     }
1609     // ----------------- BUTTON 1 //
1610     if ( has_backward )
1611     {
1612         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
1613         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1614         gtk_paint_box( style, gdkDrawable, stateType, shadowType,
1615                        gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
1616                        x+hShim+button11BoundRect.Left(), y+vShim+button11BoundRect.Top(),
1617                        button11BoundRect.GetWidth(), button11BoundRect.GetHeight() );
1618         // ----------------- ARROW 1
1619         NWCalcArrowRect( button11BoundRect, arrowRect );
1620         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1621                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
1622                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1623                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1624     }
1625     if ( has_forward2 )
1626     {
1627         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
1628         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1629         gtk_paint_box( style, gdkDrawable, stateType, shadowType,
1630                        gdkRect, GTK_WIDGET(scrollbarWidget), "stepper",
1631                        x+hShim+button12BoundRect.Left(), y+vShim+button12BoundRect.Top(),
1632                        button12BoundRect.GetWidth(), button12BoundRect.GetHeight() );
1633         // ----------------- ARROW 1
1634         NWCalcArrowRect( button12BoundRect, arrowRect );
1635         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1636                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
1637                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1638                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1639     }
1640     // ----------------- BUTTON 2
1641     if ( has_backward2 )
1642     {
1643         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton1State, &stateType, &shadowType );
1644         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1645         gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
1646                        GTK_WIDGET(scrollbarWidget), "stepper",
1647                        x+hShim+button21BoundRect.Left(), y+vShim+button21BoundRect.Top(),
1648                        button21BoundRect.GetWidth(), button21BoundRect.GetHeight() );
1649         // ----------------- ARROW 2
1650         NWCalcArrowRect( button21BoundRect, arrowRect );
1651         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1652                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button1Type, sal_True,
1653                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1654                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1655     }
1656     if ( has_forward )
1657     {
1658         NWConvertVCLStateToGTKState( pScrollbarVal->mnButton2State, &stateType, &shadowType );
1659         if ( stateType == GTK_STATE_INSENSITIVE )   stateType = GTK_STATE_NORMAL;
1660         gtk_paint_box( style, gdkDrawable, stateType, shadowType, gdkRect,
1661                        GTK_WIDGET(scrollbarWidget), "stepper",
1662                        x+hShim+button22BoundRect.Left(), y+vShim+button22BoundRect.Top(),
1663                        button22BoundRect.GetWidth(), button22BoundRect.GetHeight() );
1664         // ----------------- ARROW 2
1665         NWCalcArrowRect( button22BoundRect, arrowRect );
1666         gtk_paint_arrow( style, gdkDrawable, stateType, shadowType,
1667                          gdkRect, GTK_WIDGET(scrollbarWidget), scrollbarTag, button2Type, sal_True,
1668                          x+hShim+arrowRect.Left(), y+vShim+arrowRect.Top(),
1669                          arrowRect.GetWidth(), arrowRect.GetHeight() );
1670     }
1671 
1672     if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
1673     {
1674         g_object_unref( pixmap );
1675         return( sal_False );
1676     }
1677     g_object_unref( pixmap );
1678 
1679     return( sal_True );
1680 }
1681 
1682 //---
1683 
1684 static Rectangle NWGetScrollButtonRect( int nScreen, ControlPart nPart, Rectangle aAreaRect )
1685 {
1686     gint slider_width;
1687     gint stepper_size;
1688     gint stepper_spacing;
1689     gint trough_border;
1690 
1691     NWEnsureGTKScrollbars( nScreen );
1692 
1693     // Grab some button style attributes
1694     gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
1695                                       "slider-width", &slider_width,
1696                                       "stepper-size", &stepper_size,
1697                                       "trough-border", &trough_border,
1698                                       "stepper-spacing", &stepper_spacing, (char *)NULL );
1699 
1700     gboolean has_forward;
1701     gboolean has_forward2;
1702     gboolean has_backward;
1703     gboolean has_backward2;
1704 
1705     gtk_widget_style_get( gWidgetData[nScreen].gScrollHorizWidget,
1706                                       "has-forward-stepper", &has_forward,
1707                                       "has-secondary-forward-stepper", &has_forward2,
1708                                       "has-backward-stepper", &has_backward,
1709                                       "has-secondary-backward-stepper", &has_backward2, (char *)NULL );
1710     gint       buttonWidth;
1711     gint       buttonHeight;
1712     Rectangle  buttonRect;
1713 
1714     gint nFirst = 0;
1715     gint nSecond = 0;
1716 
1717     if ( has_forward )   nSecond += 1;
1718     if ( has_forward2 )  nFirst  += 1;
1719     if ( has_backward )  nFirst  += 1;
1720     if ( has_backward2 ) nSecond += 1;
1721 
1722     if ( ( nPart == PART_BUTTON_UP ) || ( nPart == PART_BUTTON_DOWN ) )
1723     {
1724         buttonWidth = slider_width + 2 * trough_border;
1725         buttonHeight = stepper_size + trough_border + stepper_spacing;
1726     }
1727     else
1728     {
1729         buttonWidth = stepper_size + trough_border + stepper_spacing;
1730         buttonHeight = slider_width + 2 * trough_border;
1731     }
1732 
1733     if ( nPart == PART_BUTTON_UP )
1734     {
1735         buttonHeight *= nFirst;
1736         buttonHeight -= 1;
1737         buttonRect.setX( aAreaRect.Left() );
1738         buttonRect.setY( aAreaRect.Top() );
1739     }
1740     else if ( nPart == PART_BUTTON_LEFT )
1741     {
1742         buttonWidth *= nFirst;
1743         buttonWidth -= 1;
1744         buttonRect.setX( aAreaRect.Left() );
1745         buttonRect.setY( aAreaRect.Top() );
1746     }
1747     else if ( nPart == PART_BUTTON_DOWN )
1748     {
1749         buttonHeight *= nSecond;
1750         buttonRect.setX( aAreaRect.Left() );
1751         buttonRect.setY( aAreaRect.Top() + aAreaRect.GetHeight() - buttonHeight );
1752     }
1753     else if ( nPart == PART_BUTTON_RIGHT )
1754     {
1755         buttonWidth *= nSecond;
1756         buttonRect.setX( aAreaRect.Left() + aAreaRect.GetWidth() - buttonWidth );
1757         buttonRect.setY( aAreaRect.Top() );
1758     }
1759 
1760     buttonRect.SetSize( Size( buttonWidth, buttonHeight ) );
1761 
1762     return( buttonRect );
1763 }
1764 
1765 //-------------------------------------
1766 
1767 sal_Bool GtkSalGraphics::NWPaintGTKEditBox( GdkDrawable* gdkDrawable,
1768                                         ControlType nType, ControlPart nPart,
1769                                         const Rectangle& rControlRectangle,
1770                                         const clipList& rClipList,
1771                                         ControlState nState,
1772                                         const ImplControlValue& aValue,
1773                                         const OUString& rCaption )
1774 {
1775     Rectangle       pixmapRect;
1776     GdkRectangle    clipRect;
1777 
1778     // Find the overall bounding rect of the buttons's drawing area,
1779     // plus its actual draw rect excluding adornment
1780     pixmapRect = NWGetEditBoxPixmapRect( m_nScreen, nType, nPart, rControlRectangle,
1781                                          nState, aValue, rCaption );
1782     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
1783     {
1784         clipRect.x = it->Left();
1785         clipRect.y = it->Top();
1786         clipRect.width = it->GetWidth();
1787         clipRect.height = it->GetHeight();
1788 
1789         NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, pixmapRect, nState, aValue, rCaption );
1790     }
1791 
1792     return( sal_True );
1793 }
1794 
1795 
1796 /* Take interior/exterior focus into account and return
1797  * the bounding rectangle of the edit box including
1798  * any focus requirements.
1799  */
1800 static Rectangle NWGetEditBoxPixmapRect(int nScreen,
1801                                         ControlType,
1802                                         ControlPart,
1803                                         Rectangle aAreaRect,
1804                                         ControlState,
1805                                         const ImplControlValue&,
1806                                         const OUString& )
1807 {
1808     Rectangle       pixmapRect = aAreaRect;
1809     gboolean        interiorFocus;
1810     gint            focusWidth;
1811 
1812     NWEnsureGTKEditBox( nScreen );
1813 
1814     // Grab some entry style attributes
1815     gtk_widget_style_get( gWidgetData[nScreen].gEditBoxWidget,
1816                                     "focus-line-width", &focusWidth,
1817                                     "interior-focus",   &interiorFocus, (char *)NULL );
1818 
1819     if ( !interiorFocus )
1820     {
1821         pixmapRect.Move( -(focusWidth), -(focusWidth) );
1822         pixmapRect.SetSize( Size( pixmapRect.GetWidth() + (2*(focusWidth)),
1823                                   pixmapRect.GetHeight() + (2*(focusWidth)) ) );
1824     }
1825 
1826     return( pixmapRect );
1827 }
1828 
1829 
1830 /* Paint a GTK Entry widget into the specified GdkPixmap.
1831  * All coordinates should be local to the Pixmap, NOT
1832  * screen/window coordinates.
1833  */
1834 static void NWPaintOneEditBox(  int nScreen,
1835                                 GdkDrawable * gdkDrawable,
1836                                 GdkRectangle *  gdkRect,
1837                                 ControlType         nType,
1838                                 ControlPart,
1839                                 Rectangle               aEditBoxRect,
1840                                 ControlState            nState,
1841                                 const ImplControlValue&,
1842                                 const OUString& )
1843 {
1844     GtkStateType    stateType;
1845     GtkShadowType   shadowType;
1846     GtkWidget      *widget;
1847 
1848     NWEnsureGTKButton( nScreen );
1849     NWEnsureGTKEditBox( nScreen );
1850     NWEnsureGTKSpinButton( nScreen );
1851     NWEnsureGTKCombo( nScreen );
1852     NWEnsureGTKScrolledWindow( nScreen );
1853     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1854 
1855     /* border's shadowType for gtk entries is always GTK_SHADOW_IN (see gtkentry.c)
1856     shadowType = GTK_SHADOW_IN;
1857     */
1858 
1859     switch ( nType )
1860     {
1861         case CTRL_SPINBOX:
1862             widget = gWidgetData[nScreen].gSpinButtonWidget;
1863             break;
1864 
1865         case CTRL_MULTILINE_EDITBOX:
1866             widget = gWidgetData[nScreen].gScrolledWindowWidget;
1867             break;
1868         case CTRL_COMBOBOX:
1869             widget = GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry;
1870             break;
1871 
1872         default:
1873             widget = gWidgetData[nScreen].gEditBoxWidget;
1874             break;
1875     }
1876 
1877     if ( stateType == GTK_STATE_PRELIGHT )
1878         stateType = GTK_STATE_NORMAL;
1879 
1880     // Blueprint needs to paint entry_bg with a Button widget, not an Entry widget to get
1881     // a nice white (or whatever default color) background
1882     GtkWidget* pBGWidget = widget;
1883     if( GtkSalGraphics::bNeedButtonStyleAsEditBackgroundWorkaround )
1884     {
1885         NWSetWidgetState( gWidgetData[nScreen].gBtnWidget, nState, stateType );
1886         pBGWidget = gWidgetData[nScreen].gBtnWidget;
1887     }
1888     NWSetWidgetState( widget, nState, stateType );
1889 
1890     gtk_paint_flat_box( pBGWidget->style, gdkDrawable, stateType, GTK_SHADOW_NONE,
1891                         gdkRect, pBGWidget, "entry_bg",
1892                         aEditBoxRect.Left(), aEditBoxRect.Top(),
1893                         aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
1894     gtk_paint_shadow( widget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
1895                       gdkRect, widget, "entry",
1896                       aEditBoxRect.Left(), aEditBoxRect.Top(),
1897                       aEditBoxRect.GetWidth(), aEditBoxRect.GetHeight() );
1898 
1899 }
1900 
1901 
1902 
1903 //-------------------------------------
1904 
1905 sal_Bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart,
1906                                         const Rectangle& rControlRectangle,
1907                                         const clipList&,
1908                                         ControlState nState,
1909                                         const ImplControlValue& aValue,
1910                                         const OUString& rCaption )
1911 {
1912     GdkPixmap   *       pixmap;
1913     Rectangle           pixmapRect;
1914     GtkStateType        stateType;
1915     GtkShadowType       shadowType;
1916     const SpinbuttonValue * pSpinVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue *>(&aValue) : NULL;
1917     Rectangle           upBtnRect;
1918     ControlPart     upBtnPart = PART_BUTTON_UP;
1919     ControlState        upBtnState = CTRL_STATE_ENABLED;
1920     Rectangle           downBtnRect;
1921     ControlPart     downBtnPart = PART_BUTTON_DOWN;
1922     ControlState        downBtnState = CTRL_STATE_ENABLED;
1923 
1924     NWEnsureGTKButton( m_nScreen );
1925     NWEnsureGTKSpinButton( m_nScreen );
1926     NWEnsureGTKArrow( m_nScreen );
1927 
1928     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
1929 
1930     if ( pSpinVal )
1931     {
1932         upBtnPart = pSpinVal->mnUpperPart;
1933         upBtnState = pSpinVal->mnUpperState;
1934 
1935         downBtnPart = pSpinVal->mnLowerPart;
1936         downBtnState = pSpinVal->mnLowerState;
1937     }
1938 
1939     // CTRL_SPINBUTTONS pass their area in pSpinVal, not in rControlRectangle
1940     if ( nType == CTRL_SPINBUTTONS )
1941     {
1942         if ( !pSpinVal )
1943         {
1944             std::fprintf( stderr, "Tried to draw CTRL_SPINBUTTONS, but the SpinButtons data structure didn't exist!\n" );
1945             return( false );
1946         }
1947         pixmapRect = pSpinVal->maUpperRect;
1948         pixmapRect.Union( pSpinVal->maLowerRect );
1949     }
1950     else
1951         pixmapRect = rControlRectangle;
1952 
1953 
1954     pixmap = NWGetPixmapFromScreen( pixmapRect );
1955     if ( !pixmap )
1956         return( sal_False );
1957 
1958     upBtnRect = NWGetSpinButtonRect( m_nScreen, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
1959     downBtnRect = NWGetSpinButtonRect( m_nScreen, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
1960 
1961     if ( (nType==CTRL_SPINBOX) && (nPart!=PART_ALL_BUTTONS) )
1962     {
1963         // Draw an edit field for SpinBoxes and ComboBoxes
1964         Rectangle aEditBoxRect( pixmapRect );
1965         aEditBoxRect.SetSize( Size( upBtnRect.Left() - pixmapRect.Left(), aEditBoxRect.GetHeight() ) );
1966         aEditBoxRect.setX( 0 );
1967         aEditBoxRect.setY( 0 );
1968 
1969         NWPaintOneEditBox( m_nScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption );
1970     }
1971 
1972     NWSetWidgetState( gWidgetData[m_nScreen].gSpinButtonWidget, nState, stateType );
1973     gtk_widget_style_get( gWidgetData[m_nScreen].gSpinButtonWidget, "shadow_type", &shadowType, (char *)NULL );
1974 
1975     if ( shadowType != GTK_SHADOW_NONE )
1976     {
1977         Rectangle       shadowRect( upBtnRect );
1978 
1979         shadowRect.Union( downBtnRect );
1980         gtk_paint_box( gWidgetData[m_nScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL,
1981             gWidgetData[m_nScreen].gSpinButtonWidget, "spinbutton",
1982             (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()),
1983             shadowRect.GetWidth(), shadowRect.GetHeight() );
1984     }
1985 
1986     NWPaintOneSpinButton( m_nScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption );
1987     NWPaintOneSpinButton( m_nScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption );
1988 
1989     if( !NWRenderPixmapToScreen(pixmap, pixmapRect) )
1990     {
1991         g_object_unref( pixmap );
1992         return( sal_False );
1993     }
1994 
1995     g_object_unref( pixmap );
1996     return( sal_True );
1997 }
1998 
1999 //---
2000 
2001 static Rectangle NWGetSpinButtonRect( int nScreen,
2002                                       ControlType,
2003                                       ControlPart           nPart,
2004                                       Rectangle             aAreaRect,
2005                                       ControlState,
2006                                       const ImplControlValue&,
2007                                       const OUString& )
2008 {
2009     gint            buttonSize;
2010     Rectangle       buttonRect;
2011 
2012     NWEnsureGTKSpinButton( nScreen );
2013 
2014     buttonSize = MAX( PANGO_PIXELS( pango_font_description_get_size(GTK_WIDGET(gWidgetData[nScreen].gSpinButtonWidget)->style->font_desc) ),
2015                    MIN_SPIN_ARROW_WIDTH );
2016     buttonSize -= buttonSize % 2 - 1; /* force odd */
2017     buttonRect.SetSize( Size( buttonSize + 2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness,
2018                               buttonRect.GetHeight() ) );
2019     buttonRect.setX( aAreaRect.Left() + (aAreaRect.GetWidth() - buttonRect.GetWidth()) );
2020     if ( nPart == PART_BUTTON_UP )
2021     {
2022         buttonRect.setY( aAreaRect.Top() );
2023         buttonRect.Bottom() = buttonRect.Top() + (aAreaRect.GetHeight() / 2);
2024     }
2025     else if( nPart == PART_BUTTON_DOWN )
2026     {
2027         buttonRect.setY( aAreaRect.Top() + (aAreaRect.GetHeight() / 2) );
2028         buttonRect.Bottom() = aAreaRect.Bottom(); // cover area completely
2029     }
2030     else
2031     {
2032         buttonRect.Right()  = buttonRect.Left()-1;
2033         buttonRect.Left()   = aAreaRect.Left();
2034         buttonRect.Top()    = aAreaRect.Top();
2035         buttonRect.Bottom() = aAreaRect.Bottom();
2036     }
2037 
2038     return( buttonRect );
2039 }
2040 
2041 //---
2042 
2043 static void NWPaintOneSpinButton( int nScreen,
2044                                   GdkPixmap*            pixmap,
2045                                   ControlType           nType,
2046                                   ControlPart           nPart,
2047                                   Rectangle             aAreaRect,
2048                                   ControlState          nState,
2049                                   const ImplControlValue&   aValue,
2050                                   const OUString&               rCaption )
2051 {
2052     Rectangle           buttonRect;
2053     GtkStateType        stateType;
2054     GtkShadowType       shadowType;
2055     Rectangle           arrowRect;
2056     gint                arrowSize;
2057 
2058     NWEnsureGTKSpinButton( nScreen );
2059     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2060 
2061     buttonRect = NWGetSpinButtonRect( nScreen, nType, nPart, aAreaRect, nState, aValue, rCaption );
2062 
2063     NWSetWidgetState( gWidgetData[nScreen].gSpinButtonWidget, nState, stateType );
2064     gtk_paint_box( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, shadowType, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2065             (nPart == PART_BUTTON_UP) ? "spinbutton_up" : "spinbutton_down",
2066             (buttonRect.Left() - aAreaRect.Left()), (buttonRect.Top() - aAreaRect.Top()),
2067             buttonRect.GetWidth(), buttonRect.GetHeight() );
2068 
2069     arrowSize = (buttonRect.GetWidth() - (2 * gWidgetData[nScreen].gSpinButtonWidget->style->xthickness)) - 4;
2070     arrowSize -= arrowSize % 2 - 1; /* force odd */
2071     arrowRect.SetSize( Size( arrowSize, arrowSize ) );
2072     arrowRect.setX( buttonRect.Left() + (buttonRect.GetWidth() - arrowRect.GetWidth()) / 2 );
2073     if ( nPart == PART_BUTTON_UP )
2074         arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 + 1);
2075     else
2076         arrowRect.setY( buttonRect.Top() + (buttonRect.GetHeight() - arrowRect.GetHeight()) / 2 - 1);
2077 
2078     gtk_paint_arrow( gWidgetData[nScreen].gSpinButtonWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[nScreen].gSpinButtonWidget,
2079             "spinbutton", (nPart == PART_BUTTON_UP) ? GTK_ARROW_UP : GTK_ARROW_DOWN, sal_True,
2080             (arrowRect.Left() - aAreaRect.Left()), (arrowRect.Top() - aAreaRect.Top()),
2081             arrowRect.GetWidth(), arrowRect.GetHeight() );
2082 }
2083 
2084 
2085 //-------------------------------------
2086 
2087 sal_Bool GtkSalGraphics::NWPaintGTKComboBox( GdkDrawable* gdkDrawable,
2088                                          ControlType nType, ControlPart nPart,
2089                                          const Rectangle& rControlRectangle,
2090                                          const clipList& rClipList,
2091                                          ControlState nState,
2092                                          const ImplControlValue& aValue,
2093                                          const OUString& rCaption )
2094 {
2095     Rectangle       pixmapRect;
2096     Rectangle       buttonRect;
2097     GtkStateType    stateType;
2098     GtkShadowType   shadowType;
2099     Rectangle       arrowRect;
2100     gint            x,y;
2101     GdkRectangle    clipRect;
2102 
2103     NWEnsureGTKButton( m_nScreen );
2104     NWEnsureGTKArrow( m_nScreen );
2105     NWEnsureGTKCombo( m_nScreen );
2106     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2107 
2108     // Find the overall bounding rect of the buttons's drawing area,
2109     // plus its actual draw rect excluding adornment
2110     pixmapRect = rControlRectangle;
2111     x = rControlRectangle.Left();
2112     y = rControlRectangle.Top();
2113 
2114     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
2115     NWSetWidgetState( gWidgetData[m_nScreen].gComboWidget, nState, stateType );
2116     NWSetWidgetState( gWidgetData[m_nScreen].gArrowWidget, nState, stateType );
2117 
2118     buttonRect = NWGetComboBoxButtonRect( m_nScreen, nType, PART_BUTTON_DOWN, pixmapRect, nState, aValue, rCaption );
2119     if( nPart == PART_BUTTON_DOWN )
2120         buttonRect.Left() += 1;
2121 
2122     Rectangle       aEditBoxRect( pixmapRect );
2123     aEditBoxRect.SetSize( Size( pixmapRect.GetWidth() - buttonRect.GetWidth(), aEditBoxRect.GetHeight() ) );
2124 
2125     #define ARROW_EXTENT        0.7
2126     arrowRect.SetSize( Size( (gint)(MIN_ARROW_SIZE * ARROW_EXTENT),
2127                              (gint)(MIN_ARROW_SIZE * ARROW_EXTENT) ) );
2128     arrowRect.SetPos( Point( buttonRect.Left() + (gint)((buttonRect.GetWidth() - arrowRect.GetWidth()) / 2),
2129                              buttonRect.Top() + (gint)((buttonRect.GetHeight() - arrowRect.GetHeight()) / 2) ) );
2130 
2131     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2132     {
2133         clipRect.x = it->Left();
2134         clipRect.y = it->Top();
2135         clipRect.width = it->GetWidth();
2136         clipRect.height = it->GetHeight();
2137 
2138         if( nPart == PART_ENTIRE_CONTROL )
2139             NWPaintOneEditBox( m_nScreen, gdkDrawable, &clipRect, nType, nPart, aEditBoxRect,
2140                                nState, aValue, rCaption );
2141 
2142         // Buttons must paint opaque since some themes have alpha-channel enabled buttons
2143         gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
2144                             &clipRect, m_pWindow, "base",
2145                             x+(buttonRect.Left() - pixmapRect.Left()),
2146                             y+(buttonRect.Top() - pixmapRect.Top()),
2147                             buttonRect.GetWidth(), buttonRect.GetHeight() );
2148         gtk_paint_box( GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button->style, gdkDrawable, stateType, shadowType,
2149                        &clipRect, GTK_COMBO(gWidgetData[m_nScreen].gComboWidget)->button, "button",
2150                        x+(buttonRect.Left() - pixmapRect.Left()),
2151                        y+(buttonRect.Top() - pixmapRect.Top()),
2152                        buttonRect.GetWidth(), buttonRect.GetHeight() );
2153 
2154         gtk_paint_arrow( gWidgetData[m_nScreen].gArrowWidget->style, gdkDrawable, stateType, shadowType,
2155                          &clipRect, gWidgetData[m_nScreen].gArrowWidget, "arrow", GTK_ARROW_DOWN, sal_True,
2156                          x+(arrowRect.Left() - pixmapRect.Left()), y+(arrowRect.Top() - pixmapRect.Top()),
2157                          arrowRect.GetWidth(), arrowRect.GetHeight() );
2158     }
2159 
2160     return( sal_True );
2161 }
2162 
2163 //----
2164 
2165 static Rectangle NWGetComboBoxButtonRect( int nScreen,
2166                                           ControlType,
2167                                           ControlPart nPart,
2168                                           Rectangle             aAreaRect,
2169                                           ControlState,
2170                                           const ImplControlValue&,
2171                                           const OUString& )
2172 {
2173     Rectangle   aButtonRect;
2174     gint        nArrowWidth;
2175     gint        nButtonWidth;
2176     gint        nFocusWidth;
2177     gint        nFocusPad;
2178 
2179     NWEnsureGTKArrow( nScreen );
2180 
2181     // Grab some button style attributes
2182     gtk_widget_style_get( gWidgetData[nScreen].gDropdownWidget,
2183                                     "focus-line-width", &nFocusWidth,
2184                                     "focus-padding",    &nFocusPad, (char *)NULL );
2185 
2186     nArrowWidth = MIN_ARROW_SIZE + (GTK_MISC(gWidgetData[nScreen].gArrowWidget)->xpad * 2);
2187     nButtonWidth = nArrowWidth +
2188                    ((BTN_CHILD_SPACING + gWidgetData[nScreen].gDropdownWidget->style->xthickness) * 2)
2189                    + (2 * (nFocusWidth+nFocusPad));
2190     if( nPart == PART_BUTTON_DOWN )
2191     {
2192         aButtonRect.SetSize( Size( nButtonWidth, aAreaRect.GetHeight() ) );
2193         aButtonRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - nButtonWidth,
2194                                    aAreaRect.Top() ) );
2195     }
2196     else if( nPart == PART_SUB_EDIT )
2197     {
2198         NWEnsureGTKCombo( nScreen );
2199 
2200         gint adjust_x = GTK_CONTAINER(gWidgetData[nScreen].gComboWidget)->border_width +
2201                         nFocusWidth +
2202                         nFocusPad;
2203         gint adjust_y = adjust_x + gWidgetData[nScreen].gComboWidget->style->ythickness;
2204         adjust_x     += gWidgetData[nScreen].gComboWidget->style->xthickness;
2205         aButtonRect.SetSize( Size( aAreaRect.GetWidth() - nButtonWidth - 2 * adjust_x,
2206                                    aAreaRect.GetHeight() - 2 * adjust_y ) );
2207         Point aEditPos = aAreaRect.TopLeft();
2208         aEditPos.X() += adjust_x;
2209         aEditPos.Y() += adjust_y;
2210         aButtonRect.SetPos( aEditPos );
2211     }
2212 
2213     return( aButtonRect );
2214 }
2215 
2216 //-------------------------------------
2217 
2218 
2219 
2220 sal_Bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart,
2221                                         const Rectangle& rControlRectangle,
2222                                         const clipList&,
2223                                         ControlState nState,
2224                                         const ImplControlValue& aValue,
2225                                         const OUString& )
2226 {
2227     OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM );
2228     GdkPixmap * pixmap;
2229     Rectangle       pixmapRect;
2230     Rectangle       tabRect;
2231     GtkStateType    stateType;
2232     GtkShadowType   shadowType;
2233     if( ! gWidgetData[ m_nScreen ].gCacheTabItems )
2234     {
2235         gWidgetData[ m_nScreen ].gCacheTabItems = new NWPixmapCache( m_nScreen );
2236         gWidgetData[ m_nScreen ].gCacheTabPages = new NWPixmapCache( m_nScreen );
2237     }
2238     NWPixmapCache& aCacheItems = *gWidgetData[ m_nScreen ].gCacheTabItems;
2239     NWPixmapCache& aCachePage = *gWidgetData[ m_nScreen ].gCacheTabPages;
2240 
2241     if( !aCacheItems.GetSize() )
2242         aCacheItems.SetSize( 20 );
2243     if( !aCachePage.GetSize() )
2244         aCachePage.SetSize( 1 );
2245 
2246     if ( (nType == CTRL_TAB_ITEM) && (aValue.getType() != CTRL_TAB_ITEM) )
2247     {
2248         return( false );
2249     }
2250 
2251     NWEnsureGTKButton( m_nScreen );
2252     NWEnsureGTKNotebook( m_nScreen );
2253     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2254 
2255     // Find the overall bounding rect of the buttons's drawing area,
2256     // plus its actual draw rect excluding adornment
2257     pixmapRect = rControlRectangle;
2258     if ( nType == CTRL_TAB_ITEM )
2259     {
2260         const TabitemValue *    pTabitemValue = static_cast<const TabitemValue *>(&aValue);
2261         if ( !pTabitemValue->isFirst() )
2262         {
2263             // GTK+ tabs overlap on the right edge (the top tab obscures the
2264             // left edge of the tab right "below" it, so adjust the rectangle
2265             // to draw tabs slightly large so the overlap happens
2266             pixmapRect.Move( -2, 0 );
2267             pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2, pixmapRect.GetHeight() ) );
2268         }
2269         if ( nState & CTRL_STATE_SELECTED )
2270         {
2271             // In GTK+, the selected tab is 2px taller than all other tabs
2272             pixmapRect.Move( 0, -2 );
2273             pixmapRect.Bottom() += 2;
2274             tabRect = pixmapRect;
2275             // Only draw over 1 pixel of the tab pane that this tab is drawn on top of.
2276             tabRect.Bottom() -= 1;
2277         }
2278         else
2279             tabRect = pixmapRect;
2280 
2281         // Allow the tab to draw a right border if needed
2282         tabRect.Right() -= 1;
2283 
2284         // #129732# avoid degenerate cases which might lead to crashes
2285         if( tabRect.GetWidth() <= 1 || tabRect.GetHeight() <= 1 )
2286             return false;
2287     }
2288 
2289     if( nType == CTRL_TAB_ITEM )
2290     {
2291         if( aCacheItems.Find( nType, nState, pixmapRect, &pixmap ) )
2292             return NWRenderPixmapToScreen( pixmap, pixmapRect );
2293     }
2294     else
2295     {
2296         if( aCachePage.Find( nType, nState, pixmapRect, &pixmap ) )
2297             return NWRenderPixmapToScreen( pixmap, pixmapRect );
2298     }
2299 
2300 
2301 //  gtk_widget_set_state( gWidgetData[m_nScreen].gNotebookWidget, stateType );
2302 
2303     pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(),
2304                              GetX11SalData()->GetDisplay()->GetVisual( m_nScreen ).GetDepth() );
2305     GdkRectangle paintRect;
2306     paintRect.x = paintRect.y = 0;
2307     paintRect.width = pixmapRect.GetWidth();
2308     paintRect.height = pixmapRect.GetHeight();
2309 
2310     gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL,
2311                         GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", 0, 0, -1, -1);
2312 
2313     NWSetWidgetState( gWidgetData[m_nScreen].gNotebookWidget, nState, stateType );
2314 
2315     switch( nType )
2316     {
2317         case CTRL_TAB_BODY:
2318             break;
2319 
2320         case CTRL_FIXEDBORDER:
2321         case CTRL_TAB_PANE:
2322             gtk_paint_box_gap( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
2323                 (char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 );
2324             break;
2325 
2326         case CTRL_TAB_ITEM:
2327             stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE;
2328 
2329             gtk_paint_extension( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nScreen].gNotebookWidget,
2330                 (char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()),
2331                 tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM );
2332 
2333             if ( nState & CTRL_STATE_SELECTED )
2334             {
2335                 gtk_paint_flat_box( gWidgetData[m_nScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow,
2336                     (char *)"base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 );
2337             }
2338             break;
2339 
2340         default:
2341             break;
2342     }
2343 
2344     // Crux seems to think it can make the pane without a left edge
2345     if ( nType == CTRL_FIXEDBORDER )
2346         pixmapRect.Move( 1, 0 );
2347 
2348     // cache data
2349     if( nType == CTRL_TAB_ITEM )
2350         aCacheItems.Fill( nType, nState, pixmapRect, pixmap );
2351     else
2352         aCachePage.Fill( nType, nState, pixmapRect, pixmap );
2353 
2354     sal_Bool bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect);
2355     g_object_unref( pixmap );
2356     return bSuccess;
2357 }
2358 
2359 //-------------------------------------
2360 
2361 sal_Bool GtkSalGraphics::NWPaintGTKListBox( GdkDrawable* gdkDrawable,
2362                                         ControlType nType, ControlPart nPart,
2363                                         const Rectangle& rControlRectangle,
2364                                         const clipList& rClipList,
2365                                         ControlState nState,
2366                                         const ImplControlValue& aValue,
2367                                         const OUString& rCaption )
2368 {
2369     Rectangle       pixmapRect;
2370     Rectangle       widgetRect;
2371     Rectangle       aIndicatorRect;
2372     GtkStateType    stateType;
2373     GtkShadowType   shadowType;
2374     gint            bInteriorFocus;
2375     gint            nFocusLineWidth;
2376     gint            nFocusPadding;
2377     gint            x,y;
2378     GdkRectangle    clipRect;
2379 
2380     NWEnsureGTKButton( m_nScreen );
2381     NWEnsureGTKOptionMenu( m_nScreen );
2382     NWEnsureGTKScrolledWindow( m_nScreen );
2383     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2384 
2385     // Find the overall bounding rect of the buttons's drawing area,
2386     // plus its actual draw rect excluding adornment
2387     pixmapRect = rControlRectangle;
2388     if ( nPart == PART_WINDOW )
2389     {
2390         // Make the widget a _bit_ bigger
2391         pixmapRect.SetPos( Point( pixmapRect.Left() - 1,
2392                                   pixmapRect.Top() - 1 ) );
2393         pixmapRect.SetSize( Size( pixmapRect.GetWidth() + 2,
2394                                   pixmapRect.GetHeight() + 2 ) );
2395     }
2396 
2397     widgetRect = pixmapRect;
2398     x = pixmapRect.Left();
2399     y = pixmapRect.Top();
2400 
2401     // set up references to correct drawable and cliprect
2402     NWSetWidgetState( gWidgetData[m_nScreen].gBtnWidget, nState, stateType );
2403     NWSetWidgetState( gWidgetData[m_nScreen].gOptionMenuWidget, nState, stateType );
2404     NWSetWidgetState( gWidgetData[m_nScreen].gScrolledWindowWidget, nState, stateType );
2405 
2406     if ( nPart != PART_WINDOW )
2407     {
2408         gtk_widget_style_get( gWidgetData[m_nScreen].gOptionMenuWidget,
2409             "interior_focus",   &bInteriorFocus,
2410             "focus_line_width", &nFocusLineWidth,
2411             "focus_padding",    &nFocusPadding,
2412             (char *)NULL);
2413     }
2414 
2415     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2416     {
2417         clipRect.x = it->Left();
2418         clipRect.y = it->Top();
2419         clipRect.width = it->GetWidth();
2420         clipRect.height = it->GetHeight();
2421 
2422         if ( nPart != PART_WINDOW )
2423         {
2424             // Listboxes must paint opaque since some themes have alpha-channel enabled bodies
2425             gtk_paint_flat_box( gWidgetData[m_nScreen].gBtnWidget->style, gdkDrawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
2426                                 &clipRect, m_pWindow, "base", x, y,
2427                                 pixmapRect.GetWidth(), pixmapRect.GetHeight() );
2428             gtk_paint_box( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
2429                            gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenu",
2430                            x+(widgetRect.Left() - pixmapRect.Left()),
2431                            y+(widgetRect.Top() - pixmapRect.Top()),
2432                            widgetRect.GetWidth(), widgetRect.GetHeight() );
2433             aIndicatorRect = NWGetListBoxIndicatorRect( m_nScreen, nType, nPart, widgetRect, nState,
2434                                                         aValue, rCaption );
2435             gtk_paint_tab( gWidgetData[m_nScreen].gOptionMenuWidget->style, gdkDrawable, stateType, shadowType, &clipRect,
2436                            gWidgetData[m_nScreen].gOptionMenuWidget, "optionmenutab",
2437                            x+(aIndicatorRect.Left() - pixmapRect.Left()),
2438                            y+(aIndicatorRect.Top() - pixmapRect.Top()),
2439                            aIndicatorRect.GetWidth(), aIndicatorRect.GetHeight() );
2440         }
2441         else
2442         {
2443             shadowType = GTK_SHADOW_IN;
2444 
2445             gtk_paint_shadow( gWidgetData[m_nScreen].gScrolledWindowWidget->style, gdkDrawable, GTK_STATE_NORMAL, shadowType,
2446                 &clipRect, gWidgetData[m_nScreen].gScrolledWindowWidget, "scrolled_window",
2447                 x+(widgetRect.Left() - pixmapRect.Left()), y+(widgetRect.Top() - pixmapRect.Top()),
2448                 widgetRect.GetWidth(), widgetRect.GetHeight() );
2449         }
2450     }
2451 
2452     return( sal_True );
2453 }
2454 
2455 sal_Bool GtkSalGraphics::NWPaintGTKToolbar(
2456             GdkDrawable* gdkDrawable,
2457             ControlType, ControlPart nPart,
2458             const Rectangle& rControlRectangle,
2459             const clipList& rClipList,
2460             ControlState nState, const ImplControlValue& aValue,
2461             const OUString& )
2462 {
2463     GtkStateType    stateType;
2464     GtkShadowType   shadowType;
2465     gint            x, y, w, h;
2466     gint            g_x=0, g_y=0, g_w=10, g_h=10;
2467     bool            bPaintButton = true;
2468     GtkWidget*      pButtonWidget = gWidgetData[m_nScreen].gToolbarButtonWidget;
2469     GdkRectangle    clipRect;
2470 
2471     NWEnsureGTKToolbar( m_nScreen );
2472     if( nPart == PART_BUTTON ) // toolbar buttons cannot focus in gtk
2473         nState &= ~CTRL_STATE_FOCUSED;
2474     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2475 
2476     x = rControlRectangle.Left();
2477     y = rControlRectangle.Top();
2478     w = rControlRectangle.GetWidth();
2479     h = rControlRectangle.GetHeight();
2480 
2481     // handle toolbar
2482     if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
2483     {
2484         NWSetWidgetState( gWidgetData[m_nScreen].gToolbarWidget, nState, stateType );
2485 
2486         GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
2487         if ( nState & CTRL_STATE_ENABLED )
2488             GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gToolbarWidget, GTK_SENSITIVE );
2489 
2490         if( nPart == PART_DRAW_BACKGROUND_HORZ )
2491             gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_HORIZONTAL );
2492         else
2493             gtk_toolbar_set_orientation( GTK_TOOLBAR(gWidgetData[m_nScreen].gToolbarWidget), GTK_ORIENTATION_VERTICAL );
2494     }
2495     // handle grip
2496     else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
2497     {
2498         NWSetWidgetState( gWidgetData[m_nScreen].gHandleBoxWidget, nState, stateType );
2499 
2500         GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
2501         if ( nState & CTRL_STATE_ENABLED )
2502             GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gHandleBoxWidget, GTK_SENSITIVE );
2503 
2504         gtk_handle_box_set_shadow_type( GTK_HANDLE_BOX(gWidgetData[m_nScreen].gHandleBoxWidget), shadowType );
2505 
2506         // evaluate grip rect
2507         if( aValue.getType() == CTRL_TOOLBAR )
2508         {
2509             const ToolbarValue* pVal = static_cast<const ToolbarValue*>(&aValue);
2510             g_x = pVal->maGripRect.Left();
2511             g_y = pVal->maGripRect.Top();
2512             g_w = pVal->maGripRect.GetWidth();
2513             g_h = pVal->maGripRect.GetHeight();
2514         }
2515     }
2516     // handle button
2517     else if( nPart == PART_BUTTON )
2518     {
2519         bPaintButton =
2520             (GTK_BUTTON(pButtonWidget)->relief != GTK_RELIEF_NONE)
2521             || (nState & CTRL_STATE_PRESSED)
2522             || (nState & CTRL_STATE_ROLLOVER);
2523         if( aValue.getTristateVal() == BUTTONVALUE_ON )
2524         {
2525             pButtonWidget = gWidgetData[m_nScreen].gToolbarToggleWidget;
2526             shadowType = GTK_SHADOW_IN;
2527             stateType = GTK_STATE_ACTIVE;
2528             // special case stateType value for depressed toggle buttons
2529             // cf. gtk+/gtk/gtktogglebutton.c (gtk_toggle_button_update_state)
2530             if( (nState & (CTRL_STATE_ROLLOVER|CTRL_STATE_PRESSED)) )
2531             {
2532                 stateType = GTK_STATE_PRELIGHT;
2533                 shadowType = GTK_SHADOW_OUT;
2534             }
2535             bPaintButton = true;
2536         }
2537         else
2538             stateType = GTK_STATE_PRELIGHT; // only for bPaintButton = true, in which case always rollver is meant
2539 
2540         NWSetWidgetState( pButtonWidget, nState, stateType );
2541         gtk_widget_ensure_style( pButtonWidget );
2542     }
2543 
2544     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2545     {
2546         clipRect.x = it->Left();
2547         clipRect.y = it->Top();
2548         clipRect.width = it->GetWidth();
2549         clipRect.height = it->GetHeight();
2550 
2551         // draw toolbar
2552         if( nPart == PART_DRAW_BACKGROUND_HORZ || nPart == PART_DRAW_BACKGROUND_VERT )
2553         {
2554             gtk_paint_flat_box( gWidgetData[m_nScreen].gToolbarWidget->style,
2555                                 gdkDrawable,
2556                                 (GtkStateType)GTK_STATE_NORMAL,
2557                                 GTK_SHADOW_NONE,
2558                                 &clipRect,
2559                                 gWidgetData[m_nScreen].gToolbarWidget,
2560                                 "base",
2561                                 x, y, w, h );
2562             gtk_paint_box( gWidgetData[m_nScreen].gToolbarWidget->style,
2563                            gdkDrawable,
2564                            stateType,
2565                            shadowType,
2566                            &clipRect,
2567                            gWidgetData[m_nScreen].gToolbarWidget,
2568                            "toolbar",
2569                            x, y, w, h );
2570         }
2571         // draw grip
2572         else if( nPart == PART_THUMB_HORZ || nPart == PART_THUMB_VERT )
2573         {
2574             gtk_paint_handle( gWidgetData[m_nScreen].gHandleBoxWidget->style,
2575                               gdkDrawable,
2576                               GTK_STATE_NORMAL,
2577                               GTK_SHADOW_OUT,
2578                               &clipRect,
2579                               gWidgetData[m_nScreen].gHandleBoxWidget,
2580                               "handlebox",
2581                               g_x, g_y, g_w, g_h,
2582                               nPart == PART_THUMB_HORZ ?
2583                               GTK_ORIENTATION_HORIZONTAL :
2584                               GTK_ORIENTATION_VERTICAL
2585                               );
2586         }
2587         // draw button
2588         else if( nPart == PART_BUTTON )
2589         {
2590             if( bPaintButton )
2591             {
2592                 gtk_paint_box( pButtonWidget->style, gdkDrawable,
2593                                stateType,
2594                                shadowType,
2595                                &clipRect,
2596                                pButtonWidget, "button", x, y, w, h );
2597             }
2598         }
2599     }
2600 
2601     return( sal_True );
2602 }
2603 
2604 //----
2605 
2606 sal_Bool GtkSalGraphics::NWPaintGTKMenubar(
2607             GdkDrawable* gdkDrawable,
2608             ControlType, ControlPart nPart,
2609             const Rectangle& rControlRectangle,
2610             const clipList& rClipList,
2611             ControlState nState, const ImplControlValue&,
2612             const OUString& )
2613 {
2614     GtkStateType    stateType;
2615     GtkShadowType   shadowType;
2616     GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
2617     gint            x, y, w, h;
2618     GdkRectangle    clipRect;
2619 
2620     NWEnsureGTKMenubar( m_nScreen );
2621     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2622 
2623     x = rControlRectangle.Left();
2624     y = rControlRectangle.Top();
2625     w = rControlRectangle.GetWidth();
2626     h = rControlRectangle.GetHeight();
2627 
2628     if( nPart == PART_MENU_ITEM )
2629     {
2630         if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2631         {
2632             gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenubarWidget,
2633                                   "selected_shadow_type", &selected_shadow_type,
2634                                   (char *)NULL);
2635         }
2636     }
2637 
2638     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2639     {
2640         clipRect.x = it->Left();
2641         clipRect.y = it->Top();
2642         clipRect.width = it->GetWidth();
2643         clipRect.height = it->GetHeight();
2644 
2645         // handle Menubar
2646         if( nPart == PART_ENTIRE_CONTROL )
2647         {
2648             NWSetWidgetState( gWidgetData[m_nScreen].gMenubarWidget, nState, stateType );
2649 
2650             GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
2651             if ( nState & CTRL_STATE_ENABLED )
2652                 GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenubarWidget, GTK_SENSITIVE );
2653 
2654             // #118704# for translucent menubar styles paint background first
2655             gtk_paint_flat_box( gWidgetData[m_nScreen].gMenubarWidget->style,
2656                                 gdkDrawable,
2657                                 GTK_STATE_NORMAL,
2658                                 GTK_SHADOW_NONE,
2659                                 &clipRect,
2660                                 GTK_WIDGET(m_pWindow),
2661                                 "base",
2662                                 x, y, w, h );
2663             gtk_paint_box( gWidgetData[m_nScreen].gMenubarWidget->style,
2664                            gdkDrawable,
2665                            stateType,
2666                            shadowType,
2667                            &clipRect,
2668                            gWidgetData[m_nScreen].gMenubarWidget,
2669                            "menubar",
2670                            x, y, w, h );
2671         }
2672         else if( nPart == PART_MENU_ITEM )
2673         {
2674             if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2675             {
2676                 gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenubarWidget->style,
2677                                gdkDrawable,
2678                                GTK_STATE_PRELIGHT,
2679                                selected_shadow_type,
2680                                &clipRect,
2681                                gWidgetData[m_nScreen].gMenuItemMenubarWidget,
2682                                "menuitem",
2683                                x, y, w, h);
2684             }
2685         }
2686     }
2687 
2688     return( sal_True );
2689 }
2690 
2691 sal_Bool GtkSalGraphics::NWPaintGTKPopupMenu(
2692             GdkDrawable* gdkDrawable,
2693             ControlType, ControlPart nPart,
2694             const Rectangle& rControlRectangle,
2695             const clipList& rClipList,
2696             ControlState nState, const ImplControlValue&,
2697             const OUString& )
2698 {
2699     // #i50745# gtk does not draw disabled menu entries (and crux theme
2700     // even crashes), draw them using vcl functionality.
2701     if( nPart == PART_MENU_ITEM && ! (nState & CTRL_STATE_ENABLED) )
2702         return sal_False;
2703 
2704     GtkStateType    stateType;
2705     GtkShadowType   shadowType;
2706     GtkShadowType   selected_shadow_type = GTK_SHADOW_OUT;
2707     gint            x, y, w, h;
2708     GdkRectangle    clipRect;
2709 
2710     NWEnsureGTKMenu( m_nScreen );
2711     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2712 
2713     x = rControlRectangle.Left();
2714     y = rControlRectangle.Top();
2715     w = rControlRectangle.GetWidth();
2716     h = rControlRectangle.GetHeight();
2717 
2718     if( nPart == PART_MENU_ITEM &&
2719         ( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) ) )
2720     {
2721         gtk_widget_style_get( gWidgetData[m_nScreen].gMenuItemMenuWidget,
2722                               "selected_shadow_type", &selected_shadow_type,
2723                               (char *)NULL);
2724     }
2725 
2726     NWSetWidgetState( gWidgetData[m_nScreen].gMenuWidget, nState, stateType );
2727 
2728     GTK_WIDGET_UNSET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
2729     if ( nState & CTRL_STATE_ENABLED )
2730         GTK_WIDGET_SET_FLAGS( gWidgetData[m_nScreen].gMenuWidget, GTK_SENSITIVE );
2731 
2732     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2733     {
2734         clipRect.x = it->Left();
2735         clipRect.y = it->Top();
2736         clipRect.width = it->GetWidth();
2737         clipRect.height = it->GetHeight();
2738 
2739         if( nPart == PART_ENTIRE_CONTROL )
2740         {
2741             // #118704# for translucent menubar styles paint background first
2742             gtk_paint_flat_box( gWidgetData[m_nScreen].gMenuWidget->style,
2743                                 gdkDrawable,
2744                                 GTK_STATE_NORMAL,
2745                                 GTK_SHADOW_NONE,
2746                                 &clipRect,
2747                                 GTK_WIDGET(m_pWindow),
2748                                 "base",
2749                                 x, y, w, h );
2750             gtk_paint_box( gWidgetData[m_nScreen].gMenuWidget->style,
2751                            gdkDrawable,
2752                            GTK_STATE_NORMAL,
2753                            GTK_SHADOW_OUT,
2754                            &clipRect,
2755                            gWidgetData[m_nScreen].gMenuWidget,
2756                            "menu",
2757                            x, y, w, h );
2758         }
2759         else if( nPart == PART_MENU_ITEM )
2760         {
2761             if( nState & (CTRL_STATE_SELECTED|CTRL_STATE_ROLLOVER) )
2762             {
2763                 if( nState & CTRL_STATE_ENABLED )
2764                 gtk_paint_box( gWidgetData[m_nScreen].gMenuItemMenuWidget->style,
2765                                gdkDrawable,
2766                                GTK_STATE_PRELIGHT,
2767                                selected_shadow_type,
2768                                &clipRect,
2769                                gWidgetData[m_nScreen].gMenuItemMenuWidget,
2770                                "menuitem",
2771                                x, y, w, h);
2772             }
2773         }
2774         else if( nPart == PART_MENU_ITEM_CHECK_MARK || nPart == PART_MENU_ITEM_RADIO_MARK )
2775         {
2776             GtkWidget* pWidget = (nPart == PART_MENU_ITEM_CHECK_MARK) ?
2777                                  gWidgetData[m_nScreen].gMenuItemCheckMenuWidget :
2778                                  gWidgetData[m_nScreen].gMenuItemRadioMenuWidget;
2779 
2780             GtkStateType nStateType = GTK_STATE_NORMAL;
2781             GtkShadowType nShadowType;
2782 
2783             if ( nState & CTRL_STATE_SELECTED )
2784                 nStateType = GTK_STATE_PRELIGHT;
2785 
2786             NWSetWidgetState( pWidget, nState, nStateType );
2787 
2788             if ( nState & CTRL_STATE_PRESSED )
2789                 nShadowType = GTK_SHADOW_IN;
2790             else
2791                 nShadowType = GTK_SHADOW_OUT;
2792 
2793             if ( nPart == PART_MENU_ITEM_CHECK_MARK )
2794             {
2795                 gtk_paint_check( pWidget->style,
2796                                  gdkDrawable,
2797                                  nStateType,
2798                                  nShadowType,
2799                                  &clipRect,
2800                                  gWidgetData[m_nScreen].gMenuItemMenuWidget,
2801                                  "check",
2802                                  x, y, w, h );
2803             }
2804             else
2805             {
2806                 gtk_paint_option( pWidget->style,
2807                                   gdkDrawable,
2808                                   nStateType,
2809                                   nShadowType,
2810                                   &clipRect,
2811                                   gWidgetData[m_nScreen].gMenuItemMenuWidget,
2812                                   "option",
2813                                   x, y, w, h );
2814             }
2815         }
2816     }
2817 
2818     return( sal_True );
2819 }
2820 
2821 sal_Bool GtkSalGraphics::NWPaintGTKTooltip(
2822             GdkDrawable* gdkDrawable,
2823             ControlType, ControlPart,
2824             const Rectangle& rControlRectangle,
2825             const clipList& rClipList,
2826             ControlState, const ImplControlValue&,
2827             const OUString& )
2828 {
2829     NWEnsureGTKTooltip( m_nScreen );
2830 
2831     gint            x, y, w, h;
2832     GdkRectangle    clipRect;
2833 
2834     x = rControlRectangle.Left();
2835     y = rControlRectangle.Top();
2836     w = rControlRectangle.GetWidth();
2837     h = rControlRectangle.GetHeight();
2838 
2839     for( clipList::const_iterator it = rClipList.begin(); it != rClipList.end(); ++it )
2840     {
2841         clipRect.x = it->Left();
2842         clipRect.y = it->Top();
2843         clipRect.width = it->GetWidth();
2844         clipRect.height = it->GetHeight();
2845 
2846         gtk_paint_flat_box( gWidgetData[m_nScreen].gTooltipPopup->style,
2847                             gdkDrawable,
2848                             GTK_STATE_NORMAL,
2849                             GTK_SHADOW_OUT,
2850                             &clipRect,
2851                             gWidgetData[m_nScreen].gTooltipPopup,
2852                             "tooltip",
2853                             x, y, w, h );
2854     }
2855 
2856     return( sal_True );
2857 }
2858 
2859 sal_Bool GtkSalGraphics::NWPaintGTKListNode(
2860             GdkDrawable*,
2861             ControlType, ControlPart,
2862             const Rectangle& rControlRectangle,
2863             const clipList&,
2864             ControlState nState, const ImplControlValue& rValue,
2865             const OUString& )
2866 {
2867     NWEnsureGTKTreeView( m_nScreen );
2868 
2869     Rectangle aRect( rControlRectangle );
2870     aRect.Left() -= 2;
2871     aRect.Right() += 2;
2872     aRect.Top() -= 2;
2873     aRect.Bottom() += 2;
2874     gint            w, h;
2875     w = aRect.GetWidth();
2876     h = aRect.GetHeight();
2877 
2878     GtkStateType    stateType;
2879     GtkShadowType   shadowType;
2880     NWConvertVCLStateToGTKState( nState, &stateType, &shadowType );
2881 
2882     ButtonValue aButtonValue = rValue.getTristateVal();
2883     GtkExpanderStyle eStyle = GTK_EXPANDER_EXPANDED;
2884 
2885     switch( aButtonValue )
2886     {
2887         case BUTTONVALUE_ON: eStyle = GTK_EXPANDER_EXPANDED;break;
2888         case BUTTONVALUE_OFF: eStyle = GTK_EXPANDER_COLLAPSED; break;
2889         default:
2890             break;
2891     }
2892 
2893     GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect );
2894     if( ! pixmap )
2895         return sal_False;
2896 
2897     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2898     gtk_paint_expander( gWidgetData[m_nScreen].gTreeView->style,
2899                         pixDrawable,
2900                         stateType,
2901                         NULL,
2902                         gWidgetData[m_nScreen].gTreeView,
2903                         "treeview",
2904                         w/2, h/2,
2905                         eStyle );
2906 
2907     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, aRect );
2908     g_object_unref( pixmap );
2909 
2910     return bRet;
2911 }
2912 
2913 sal_Bool GtkSalGraphics::NWPaintGTKProgress(
2914             GdkDrawable*,
2915             ControlType, ControlPart,
2916             const Rectangle& rControlRectangle,
2917             const clipList&,
2918             ControlState, const ImplControlValue& rValue,
2919             const OUString& )
2920 {
2921     NWEnsureGTKProgressBar( m_nScreen );
2922 
2923     gint            w, h;
2924     w = rControlRectangle.GetWidth();
2925     h = rControlRectangle.GetHeight();
2926 
2927     long nProgressWidth = rValue.getNumericVal();
2928 
2929     GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) );
2930     if( ! pixmap )
2931         return sal_False;
2932 
2933     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2934 
2935     // paint background
2936     gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
2937                         pixDrawable,
2938                         GTK_STATE_NORMAL,
2939                         GTK_SHADOW_NONE,
2940                         NULL,
2941                         gWidgetData[m_nScreen].gProgressBar,
2942                         "trough",
2943                         0, 0, w, h );
2944     if( nProgressWidth > 0 )
2945     {
2946         // paint progress
2947         if( Application::GetSettings().GetLayoutRTL() )
2948         {
2949             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
2950                            pixDrawable,
2951                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
2952                            NULL,
2953                            gWidgetData[m_nScreen].gProgressBar,
2954                            "bar",
2955                            w-nProgressWidth, 0, nProgressWidth, h
2956                            );
2957         }
2958         else
2959         {
2960             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
2961                            pixDrawable,
2962                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
2963                            NULL,
2964                            gWidgetData[m_nScreen].gProgressBar,
2965                            "bar",
2966                            0, 0, nProgressWidth, h
2967                            );
2968         }
2969     }
2970 
2971     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
2972     g_object_unref( pixmap );
2973 
2974     return bRet;
2975 }
2976 
2977 sal_Bool GtkSalGraphics::NWPaintGTKSlider(
2978             GdkDrawable*,
2979             ControlType, ControlPart nPart,
2980             const Rectangle& rControlRectangle,
2981             const clipList&,
2982             ControlState nState, const ImplControlValue& rValue,
2983             const OUString& )
2984 {
2985     OSL_ASSERT( rValue.getType() == CTRL_SLIDER );
2986     NWEnsureGTKSlider( m_nScreen );
2987 
2988     gint            w, h;
2989     w = rControlRectangle.GetWidth();
2990     h = rControlRectangle.GetHeight();
2991 
2992     const SliderValue* pVal = static_cast<const SliderValue*>(&rValue);
2993 
2994     GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle );
2995     if( ! pixmap )
2996         return sal_False;
2997 
2998     GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap );
2999     GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA)
3000                          ? GTK_WIDGET(gWidgetData[m_nScreen].gHScale)
3001                          : GTK_WIDGET(gWidgetData[m_nScreen].gVScale);
3002     const gchar* pDetail = (nPart == PART_TRACK_HORZ_AREA) ? "hscale" : "vscale";
3003     GtkOrientation eOri = (nPart == PART_TRACK_HORZ_AREA) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
3004     GtkStateType eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE;
3005     gint slider_width = 10;
3006     gint slider_length = 10;
3007     gint trough_border = 0;
3008     gtk_widget_style_get( pWidget,
3009                           "slider-width", &slider_width,
3010                           "slider-length", &slider_length,
3011                           "trough-border", &trough_border,
3012                           NULL);
3013 
3014     eState = (nState & CTRL_STATE_ENABLED) ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
3015     if( nPart == PART_TRACK_HORZ_AREA )
3016     {
3017         gtk_paint_box( pWidget->style,
3018                        pixDrawable,
3019                        eState,
3020                        GTK_SHADOW_IN,
3021                        NULL,
3022                        pWidget,
3023                        "trough",
3024                        0, (h-slider_width-2*trough_border)/2, w, slider_width + 2*trough_border);
3025         gint x = (w - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3026         gtk_paint_slider( pWidget->style,
3027                           pixDrawable,
3028                           eState,
3029                           GTK_SHADOW_OUT,
3030                           NULL,
3031                           pWidget,
3032                           pDetail,
3033                           x, (h-slider_width)/2,
3034                           slider_length, slider_width,
3035                           eOri );
3036     }
3037     else
3038     {
3039         gtk_paint_box( pWidget->style,
3040                        pixDrawable,
3041                        eState,
3042                        GTK_SHADOW_IN,
3043                        NULL,
3044                        pWidget,
3045                        "trough",
3046                        (w-slider_width-2*trough_border)/2, 0, slider_width + 2*trough_border, h);
3047         gint y = (h - slider_length + 1) * (pVal->mnCur - pVal->mnMin) / (pVal->mnMax - pVal->mnMin);
3048         gtk_paint_slider( pWidget->style,
3049                           pixDrawable,
3050                           eState,
3051                           GTK_SHADOW_OUT,
3052                           NULL,
3053                           pWidget,
3054                           pDetail,
3055                           (w-slider_width)/2, y,
3056                           slider_width, slider_length,
3057                           eOri );
3058     }
3059     #if 0
3060     // paint background
3061     gtk_paint_flat_box( gWidgetData[m_nScreen].gProgressBar->style,
3062                         pixDrawable,
3063                         GTK_STATE_NORMAL,
3064                         GTK_SHADOW_NONE,
3065                         NULL,
3066                         gWidgetData[m_nScreen].gProgressBar,
3067                         "trough",
3068                         0, 0, w, h );
3069     if( nProgressWidth > 0 )
3070     {
3071         // paint progress
3072         if( Application::GetSettings().GetLayoutRTL() )
3073         {
3074             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
3075                            pixDrawable,
3076                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3077                            NULL,
3078                            gWidgetData[m_nScreen].gProgressBar,
3079                            "bar",
3080                            w-nProgressWidth, 0, nProgressWidth, h
3081                            );
3082         }
3083         else
3084         {
3085             gtk_paint_box( gWidgetData[m_nScreen].gProgressBar->style,
3086                            pixDrawable,
3087                            GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
3088                            NULL,
3089                            gWidgetData[m_nScreen].gProgressBar,
3090                            "bar",
3091                            0, 0, nProgressWidth, h
3092                            );
3093         }
3094     }
3095     #endif
3096 
3097     sal_Bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle );
3098     g_object_unref( pixmap );
3099 
3100     return bRet;
3101 }
3102 
3103 //----
3104 
3105 static Rectangle NWGetListBoxButtonRect( int nScreen,
3106                                          ControlType,
3107                                          ControlPart    nPart,
3108                                          Rectangle      aAreaRect,
3109                                          ControlState,
3110                                          const ImplControlValue&,
3111                                          const OUString& )
3112 {
3113     Rectangle       aPartRect;
3114     GtkRequisition *pIndicatorSize = NULL;
3115     GtkBorder      *pIndicatorSpacing = NULL;
3116     gint            width = 13; // GTK+ default
3117     gint            right = 5;  // GTK+ default
3118     gint            nButtonAreaWidth = 0;
3119     gint            xthickness = 0;
3120 
3121     NWEnsureGTKOptionMenu( nScreen );
3122 
3123     gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3124             "indicator_size",   &pIndicatorSize,
3125             "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3126 
3127     if ( pIndicatorSize )
3128         width = pIndicatorSize->width;
3129 
3130     if ( pIndicatorSpacing )
3131         right = pIndicatorSpacing->right;
3132 
3133     Size aPartSize( 0, aAreaRect.GetHeight() );
3134     Point aPartPos ( 0, aAreaRect.Top() );
3135 
3136     xthickness = gWidgetData[nScreen].gOptionMenuWidget->style->xthickness;
3137     nButtonAreaWidth = width + right + (xthickness * 2);
3138     switch( nPart )
3139     {
3140         case PART_BUTTON_DOWN:
3141             aPartSize.Width() = nButtonAreaWidth;
3142             aPartPos.X() = aAreaRect.Left() + aAreaRect.GetWidth() - aPartSize.Width();
3143             break;
3144 
3145         case PART_SUB_EDIT:
3146             aPartSize.Width() = aAreaRect.GetWidth() - nButtonAreaWidth - xthickness;
3147             aPartPos.X() = aAreaRect.Left() + xthickness;
3148             break;
3149 
3150         default:
3151             aPartSize.Width() = aAreaRect.GetWidth();
3152             aPartPos.X() = aAreaRect.Left();
3153             break;
3154     }
3155     aPartRect = Rectangle( aPartPos, aPartSize );
3156 
3157     if ( pIndicatorSize )
3158         gtk_requisition_free( pIndicatorSize );
3159     if ( pIndicatorSpacing )
3160         gtk_border_free( pIndicatorSpacing );
3161 
3162     return( aPartRect );
3163 }
3164 
3165 //----
3166 
3167 static Rectangle NWGetListBoxIndicatorRect( int nScreen,
3168                                             ControlType,
3169                                             ControlPart,
3170                                             Rectangle               aAreaRect,
3171                                             ControlState,
3172                                             const ImplControlValue&,
3173                                             const OUString& )
3174 {
3175     Rectangle       aIndicatorRect;
3176     GtkRequisition *pIndicatorSize = NULL;
3177     GtkBorder      *pIndicatorSpacing = NULL;
3178     gint            width = 13; // GTK+ default
3179     gint            height = 13;    // GTK+ default
3180     gint            right = 5;  // GTK+ default
3181 
3182     NWEnsureGTKOptionMenu( nScreen );
3183 
3184     gtk_widget_style_get( gWidgetData[nScreen].gOptionMenuWidget,
3185             "indicator_size",   &pIndicatorSize,
3186             "indicator_spacing",&pIndicatorSpacing, (char *)NULL);
3187 
3188     if ( pIndicatorSize )
3189     {
3190         width = pIndicatorSize->width;
3191         height = pIndicatorSize->height;
3192     }
3193 
3194     if ( pIndicatorSpacing )
3195         right = pIndicatorSpacing->right;
3196 
3197     aIndicatorRect.SetSize( Size( width, height ) );
3198     aIndicatorRect.SetPos( Point( aAreaRect.Left() + aAreaRect.GetWidth() - width - right - gWidgetData[nScreen].gOptionMenuWidget->style->xthickness,
3199                                   aAreaRect.Top() + ((aAreaRect.GetHeight() - height) / 2) ) );
3200 
3201     // If height is odd, move the indicator down 1 pixel
3202     if ( aIndicatorRect.GetHeight() % 2 )
3203         aIndicatorRect.Move( 0, 1 );
3204 
3205     if ( pIndicatorSize )
3206         gtk_requisition_free( pIndicatorSize );
3207     if ( pIndicatorSpacing )
3208         gtk_border_free( pIndicatorSpacing );
3209 
3210     return( aIndicatorRect );
3211 }
3212 
3213 static Rectangle NWGetToolbarRect(  int nScreen,
3214                                     ControlType,
3215                                     ControlPart             nPart,
3216                                     Rectangle               aAreaRect,
3217                                     ControlState,
3218                                     const ImplControlValue&,
3219                                     const OUString& )
3220 {
3221     Rectangle aRet;
3222 
3223     if( nPart == PART_DRAW_BACKGROUND_HORZ ||
3224         nPart == PART_DRAW_BACKGROUND_VERT )
3225         aRet = aAreaRect;
3226     else if( nPart == PART_THUMB_HORZ )
3227         aRet = Rectangle( Point( 0, 0 ), Size( aAreaRect.GetWidth(), 10 ) );
3228     else if( nPart == PART_THUMB_VERT )
3229         aRet = Rectangle( Point( 0, 0 ), Size( 10, aAreaRect.GetHeight() ) );
3230     else if( nPart == PART_BUTTON )
3231     {
3232         aRet = aAreaRect;
3233 
3234         NWEnsureGTKToolbar( nScreen );
3235 
3236         gint nMinWidth =
3237             2*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness
3238             + 1 // CHILD_SPACING constant, found in gtk_button.c
3239             + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->xthickness; // Murphy factor
3240         gint nMinHeight =
3241             2*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness
3242             + 1 // CHILD_SPACING constant, found in gtk_button.c
3243             + 3*gWidgetData[nScreen].gToolbarButtonWidget->style->ythickness; // Murphy factor
3244 
3245         gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarButtonWidget );
3246         if( aAreaRect.GetWidth() < nMinWidth )
3247             aRet.Right() = aRet.Left() + nMinWidth;
3248         if( aAreaRect.GetHeight() < nMinHeight  )
3249             aRet.Bottom() = aRet.Top() + nMinHeight;
3250     }
3251 
3252     return aRet;
3253 }
3254 
3255 /************************************************************************
3256  * helper for GtkSalFrame
3257  ************************************************************************/
3258 static inline Color getColor( const GdkColor& rCol )
3259 {
3260     return Color( rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3261 }
3262 
3263 #if OSL_DEBUG_LEVEL > 1
3264 
3265 void printColor( const char* name, const GdkColor& rCol )
3266 {
3267     std::fprintf( stderr, "   %s = 0x%2x 0x%2x 0x%2x\n",
3268              name,
3269              rCol.red >> 8, rCol.green >> 8, rCol.blue >> 8 );
3270 }
3271 
3272 void printStyleColors( GtkStyle* pStyle )
3273 {
3274     static const char* pStates[] = { "NORMAL", "ACTIVE", "PRELIGHT", "SELECTED", "INSENSITIVE" };
3275 
3276     for( int i = 0; i < 5; i++ )
3277     {
3278         std::fprintf( stderr, "state %s colors:\n", pStates[i] );
3279         printColor( "bg     ", pStyle->bg[i] );
3280         printColor( "fg     ", pStyle->fg[i] );
3281         printColor( "light  ", pStyle->light[i] );
3282         printColor( "dark   ", pStyle->dark[i] );
3283         printColor( "mid    ", pStyle->mid[i] );
3284         printColor( "text   ", pStyle->text[i] );
3285         printColor( "base   ", pStyle->base[i] );
3286         printColor( "text_aa", pStyle->text_aa[i] );
3287     }
3288 }
3289 #endif
3290 
3291 void GtkSalGraphics::updateSettings( AllSettings& rSettings )
3292 {
3293     // get the widgets in place
3294     NWEnsureGTKMenu( m_nScreen );
3295     NWEnsureGTKMenubar( m_nScreen );
3296     NWEnsureGTKScrollbars( m_nScreen );
3297     NWEnsureGTKEditBox( m_nScreen );
3298     NWEnsureGTKTooltip( m_nScreen );
3299 
3300     gtk_widget_ensure_style( m_pWindow );
3301     GtkStyle* pStyle = gtk_widget_get_style( m_pWindow );
3302 
3303     StyleSettings aStyleSet = rSettings.GetStyleSettings();
3304 
3305 #if OSL_DEBUG_LEVEL > 2
3306     printStyleColors( pStyle );
3307 #endif
3308 
3309     // text colors
3310     Color aTextColor = getColor( pStyle->text[GTK_STATE_NORMAL] );
3311     aStyleSet.SetDialogTextColor( aTextColor );
3312     aStyleSet.SetButtonTextColor( aTextColor );
3313     aStyleSet.SetRadioCheckTextColor( aTextColor );
3314     aStyleSet.SetGroupTextColor( aTextColor );
3315     aStyleSet.SetLabelTextColor( aTextColor );
3316     aStyleSet.SetInfoTextColor( aTextColor );
3317     aStyleSet.SetWindowTextColor( aTextColor );
3318     aStyleSet.SetFieldTextColor( aTextColor );
3319 
3320     // Tooltip colors
3321     GtkStyle* pTooltipStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gTooltipPopup );
3322     aTextColor = getColor( pTooltipStyle->fg[ GTK_STATE_NORMAL ] );
3323     aStyleSet.SetHelpTextColor( aTextColor );
3324 
3325     // mouse over text colors
3326     aTextColor = getColor( pStyle->fg[ GTK_STATE_PRELIGHT ] );
3327     aStyleSet.SetButtonRolloverTextColor( aTextColor );
3328     aStyleSet.SetFieldRolloverTextColor( aTextColor );
3329 
3330     // background colors
3331     Color aBackColor = getColor( pStyle->bg[GTK_STATE_NORMAL] );
3332     Color aBackFieldColor = getColor( pStyle->base[ GTK_STATE_NORMAL ] );
3333     aStyleSet.Set3DColors( aBackColor );
3334     aStyleSet.SetFaceColor( aBackColor );
3335     aStyleSet.SetDialogColor( aBackColor );
3336     aStyleSet.SetWorkspaceColor( aBackColor );
3337     aStyleSet.SetFieldColor( aBackFieldColor );
3338     aStyleSet.SetWindowColor( aBackFieldColor );
3339 //    aStyleSet.SetHelpColor( aBackColor );
3340     // ancient wisdom tells us a mystic algorithm how to set checked color
3341     if( aBackColor == COL_LIGHTGRAY )
3342         aStyleSet.SetCheckedColor( Color( 0xCC, 0xCC, 0xCC ) );
3343     else
3344     {
3345         Color aColor2 = aStyleSet.GetLightColor();
3346         Color aCheck( (sal_uInt8)(((sal_uInt16)aBackColor.GetRed()+(sal_uInt16)aColor2.GetRed())/2),
3347                       (sal_uInt8)(((sal_uInt16)aBackColor.GetGreen()+(sal_uInt16)aColor2.GetGreen())/2),
3348                       (sal_uInt8)(((sal_uInt16)aBackColor.GetBlue()+(sal_uInt16)aColor2.GetBlue())/2)
3349                       );
3350         aStyleSet.SetCheckedColor( aCheck );
3351     }
3352 
3353     // highlighting colors
3354     Color aHighlightColor = getColor( pStyle->base[GTK_STATE_SELECTED] );
3355     Color aHighlightTextColor = getColor( pStyle->text[GTK_STATE_SELECTED] );
3356     aStyleSet.SetHighlightColor( aHighlightColor );
3357     aStyleSet.SetHighlightTextColor( aHighlightTextColor );
3358 
3359     if( ! gtk_check_version( 2, 10, 0 ) ) // link colors came in with 2.10, avoid an assertion
3360     {
3361         // hyperlink colors
3362         GdkColor *link_color = NULL;
3363         gtk_widget_style_get (m_pWindow, "link-color", &link_color, NULL);
3364         if (link_color)
3365         {
3366             aStyleSet.SetLinkColor(getColor(*link_color));
3367             gdk_color_free (link_color);
3368             link_color = NULL;
3369         }
3370         gtk_widget_style_get (m_pWindow, "visited-link-color", &link_color, NULL);
3371         if (link_color)
3372         {
3373             aStyleSet.SetVisitedLinkColor(getColor(*link_color));
3374             gdk_color_free (link_color);
3375         }
3376     }
3377 
3378     // Tab colors
3379     aStyleSet.SetActiveTabColor( aBackFieldColor ); // same as the window color.
3380     Color aSelectedBackColor = getColor( pStyle->bg[GTK_STATE_ACTIVE] );
3381     aStyleSet.SetInactiveTabColor( aSelectedBackColor );
3382 
3383     // menu disabled entries handling
3384     aStyleSet.SetSkipDisabledInMenus( sal_True );
3385     // menu colors
3386     GtkStyle* pMenuStyle = gtk_widget_get_style( gWidgetData[m_nScreen].gMenuWidget );
3387     GtkStyle* pMenuItemStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenuItemMenuWidget );
3388     GtkStyle* pMenubarStyle = gtk_rc_get_style( gWidgetData[m_nScreen].gMenubarWidget );
3389     GtkStyle* pMenuTextStyle = gtk_rc_get_style( gtk_bin_get_child( GTK_BIN(gWidgetData[m_nScreen].gMenuItemMenuWidget) ) );
3390 
3391     aBackColor = getColor( pMenubarStyle->bg[GTK_STATE_NORMAL] );
3392     aStyleSet.SetMenuBarColor( aBackColor );
3393     aBackColor = getColor( pMenuStyle->bg[GTK_STATE_NORMAL] );
3394     aTextColor = getColor( pMenuTextStyle->fg[GTK_STATE_NORMAL] );
3395     aStyleSet.SetMenuColor( aBackColor );
3396     aStyleSet.SetMenuTextColor( aTextColor );
3397 
3398     aTextColor = getColor( pMenubarStyle->fg[GTK_STATE_NORMAL] );
3399     aStyleSet.SetMenuBarTextColor( aTextColor );
3400 
3401 #if OSL_DEBUG_LEVEL > 1
3402     std::fprintf( stderr, "==\n" );
3403     std::fprintf( stderr, "MenuColor = %x (%d)\n", (int)aStyleSet.GetMenuColor().GetColor(), aStyleSet.GetMenuColor().GetLuminance() );
3404     std::fprintf( stderr, "MenuTextColor = %x (%d)\n", (int)aStyleSet.GetMenuTextColor().GetColor(), aStyleSet.GetMenuTextColor().GetLuminance() );
3405     std::fprintf( stderr, "MenuBarColor = %x (%d)\n", (int)aStyleSet.GetMenuBarColor().GetColor(), aStyleSet.GetMenuBarColor().GetLuminance() );
3406     std::fprintf( stderr, "MenuBarTextColor = %x (%d)\n", (int)aStyleSet.GetMenuBarTextColor().GetColor(), aStyleSet.GetMenuBarTextColor().GetLuminance() );
3407     std::fprintf( stderr, "LightColor = %x (%d)\n", (int)aStyleSet.GetLightColor().GetColor(), aStyleSet.GetLightColor().GetLuminance() );
3408     std::fprintf( stderr, "ShadowColor = %x (%d)\n", (int)aStyleSet.GetShadowColor().GetColor(), aStyleSet.GetShadowColor().GetLuminance() );
3409 #endif
3410 
3411     // Awful hack for menu separators in the Sonar and similar themes.
3412     // If the menu color is not too dark, and the menu text color is lighter,
3413     // make the "light" color lighter than the menu color and the "shadow"
3414     // color darker than it.
3415     if ( aStyleSet.GetMenuColor().GetLuminance() >= 32 &&
3416      aStyleSet.GetMenuColor().GetLuminance() <= aStyleSet.GetMenuTextColor().GetLuminance() )
3417     {
3418       Color temp = aStyleSet.GetMenuColor();
3419       temp.IncreaseLuminance( 8 );
3420       aStyleSet.SetLightColor( temp );
3421       temp = aStyleSet.GetMenuColor();
3422       temp.DecreaseLuminance( 16 );
3423       aStyleSet.SetShadowColor( temp );
3424     }
3425 
3426     aHighlightColor = getColor( pMenuItemStyle->bg[ GTK_STATE_SELECTED ] );
3427     aHighlightTextColor = getColor( pMenuTextStyle->fg[ GTK_STATE_PRELIGHT ] );
3428     if( aHighlightColor == aHighlightTextColor )
3429         aHighlightTextColor = (aHighlightColor.GetLuminance() < 128) ? Color( COL_WHITE ) : Color( COL_BLACK );
3430     aStyleSet.SetMenuHighlightColor( aHighlightColor );
3431     aStyleSet.SetMenuHighlightTextColor( aHighlightTextColor );
3432 
3433     // UI font
3434     OString aFamily     = pango_font_description_get_family( pStyle->font_desc );
3435     int nPangoHeight    = pango_font_description_get_size( pStyle->font_desc );
3436     PangoStyle  eStyle  = pango_font_description_get_style( pStyle->font_desc );
3437     PangoWeight eWeight = pango_font_description_get_weight( pStyle->font_desc );
3438     PangoStretch eStretch = pango_font_description_get_stretch( pStyle->font_desc );
3439 
3440     psp::FastPrintFontInfo aInfo;
3441     // set family name
3442     aInfo.m_aFamilyName = OStringToOUString( aFamily, RTL_TEXTENCODING_UTF8 );
3443     // set italic
3444     switch( eStyle )
3445     {
3446         case PANGO_STYLE_NORMAL:    aInfo.m_eItalic = psp::italic::Upright;break;
3447         case PANGO_STYLE_ITALIC:    aInfo.m_eItalic = psp::italic::Italic;break;
3448         case PANGO_STYLE_OBLIQUE:   aInfo.m_eItalic = psp::italic::Oblique;break;
3449     }
3450     // set weight
3451     if( eWeight <= PANGO_WEIGHT_ULTRALIGHT )
3452         aInfo.m_eWeight = psp::weight::UltraLight;
3453     else if( eWeight <= PANGO_WEIGHT_LIGHT )
3454         aInfo.m_eWeight = psp::weight::Light;
3455     else if( eWeight <= PANGO_WEIGHT_NORMAL )
3456         aInfo.m_eWeight = psp::weight::Normal;
3457     else if( eWeight <= PANGO_WEIGHT_BOLD )
3458         aInfo.m_eWeight = psp::weight::Bold;
3459     else
3460         aInfo.m_eWeight = psp::weight::UltraBold;
3461     // set width
3462     switch( eStretch )
3463     {
3464         case PANGO_STRETCH_ULTRA_CONDENSED: aInfo.m_eWidth = psp::width::UltraCondensed;break;
3465         case PANGO_STRETCH_EXTRA_CONDENSED: aInfo.m_eWidth = psp::width::ExtraCondensed;break;
3466         case PANGO_STRETCH_CONDENSED:       aInfo.m_eWidth = psp::width::Condensed;break;
3467         case PANGO_STRETCH_SEMI_CONDENSED:  aInfo.m_eWidth = psp::width::SemiCondensed;break;
3468         case PANGO_STRETCH_NORMAL:          aInfo.m_eWidth = psp::width::Normal;break;
3469         case PANGO_STRETCH_SEMI_EXPANDED:   aInfo.m_eWidth = psp::width::SemiExpanded;break;
3470         case PANGO_STRETCH_EXPANDED:        aInfo.m_eWidth = psp::width::Expanded;break;
3471         case PANGO_STRETCH_EXTRA_EXPANDED:  aInfo.m_eWidth = psp::width::ExtraExpanded;break;
3472         case PANGO_STRETCH_ULTRA_EXPANDED:  aInfo.m_eWidth = psp::width::UltraExpanded;break;
3473     }
3474 
3475 #if OSL_DEBUG_LEVEL > 1
3476     std::fprintf( stderr, "font name BEFORE system match: \"%s\"\n", aFamily.getStr() );
3477 #endif
3478 
3479     // match font to e.g. resolve "Sans"
3480     psp::PrintFontManager::get().matchFont( aInfo, rSettings.GetUILocale() );
3481 
3482 #if OSL_DEBUG_LEVEL > 1
3483     std::fprintf( stderr, "font match %s, name AFTER: \"%s\"\n",
3484              aInfo.m_nID != 0 ? "succeeded" : "failed",
3485              OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
3486 #endif
3487 
3488     sal_Int32 nDispDPIY = GetDisplay()->GetResolution().B();
3489     int nPointHeight = 0;
3490     static gboolean(*pAbso)(const PangoFontDescription*) =
3491         (gboolean(*)(const PangoFontDescription*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "pango_font_description_get_size_is_absolute" );
3492 
3493     if( pAbso && pAbso( pStyle->font_desc ) )
3494         nPointHeight = (nPangoHeight * 72 + nDispDPIY*PANGO_SCALE/2) / (nDispDPIY * PANGO_SCALE);
3495     else
3496         nPointHeight = nPangoHeight/PANGO_SCALE;
3497 
3498     Font aFont( aInfo.m_aFamilyName, Size( 0, nPointHeight ) );
3499     if( aInfo.m_eWeight != psp::weight::Unknown )
3500         aFont.SetWeight( PspGraphics::ToFontWeight( aInfo.m_eWeight ) );
3501     if( aInfo.m_eWidth != psp::width::Unknown )
3502         aFont.SetWidthType( PspGraphics::ToFontWidth( aInfo.m_eWidth ) );
3503     if( aInfo.m_eItalic != psp::italic::Unknown )
3504         aFont.SetItalic( PspGraphics::ToFontItalic( aInfo.m_eItalic ) );
3505     if( aInfo.m_ePitch != psp::pitch::Unknown )
3506         aFont.SetPitch( PspGraphics::ToFontPitch( aInfo.m_ePitch ) );
3507 
3508     aStyleSet.SetAppFont( aFont );
3509     aStyleSet.SetHelpFont( aFont );
3510     aStyleSet.SetTitleFont( aFont );
3511     aStyleSet.SetFloatTitleFont( aFont );
3512     aStyleSet.SetMenuFont( aFont );
3513     aStyleSet.SetToolFont( aFont );
3514     aStyleSet.SetLabelFont( aFont );
3515     aStyleSet.SetInfoFont( aFont );
3516     aStyleSet.SetRadioCheckFont( aFont );
3517     aStyleSet.SetPushButtonFont( aFont );
3518     aStyleSet.SetFieldFont( aFont );
3519     aStyleSet.SetIconFont( aFont );
3520     aStyleSet.SetGroupFont( aFont );
3521 
3522     // get cursor blink time
3523     GtkSettings *pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gEditBoxWidget );
3524     gboolean blink = false;
3525 
3526     g_object_get( pSettings, "gtk-cursor-blink", &blink, (char *)NULL );
3527     if( blink )
3528     {
3529         gint blink_time = STYLE_CURSOR_NOBLINKTIME;
3530         g_object_get( pSettings, "gtk-cursor-blink-time", &blink_time, (char *)NULL );
3531         // set the blink_time if there is a setting and it is reasonable
3532         // else leave the default value
3533         if( blink_time > 100 && blink_time != gint(STYLE_CURSOR_NOBLINKTIME) )
3534             aStyleSet.SetCursorBlinkTime( blink_time/2 );
3535     }
3536     else
3537         aStyleSet.SetCursorBlinkTime( STYLE_CURSOR_NOBLINKTIME );
3538 
3539     gboolean showmenuicons = true;
3540     pSettings = gtk_widget_get_settings( gWidgetData[m_nScreen].gImageMenuItem );
3541     g_object_get( pSettings, "gtk-menu-images", &showmenuicons, (char *)NULL );
3542     aStyleSet.SetUseImagesInMenus( showmenuicons );
3543 
3544     // set scrollbar settings
3545     gint slider_width = 14;
3546     gint trough_border = 1;
3547     gint min_slider_length = 21;
3548 
3549     // Grab some button style attributes
3550     gtk_widget_style_get( gWidgetData[m_nScreen].gScrollHorizWidget,
3551                           "slider-width", &slider_width,
3552                           "trough-border", &trough_border,
3553                           "min-slider-length", &min_slider_length,
3554                           (char *)NULL );
3555     gint magic = trough_border ? 1 : 0;
3556     aStyleSet.SetScrollBarSize( slider_width + 2*trough_border );
3557     aStyleSet.SetMinThumbSize( min_slider_length - magic );
3558 
3559     // preferred icon style
3560     gchar* pIconThemeName = NULL;
3561     g_object_get( gtk_settings_get_default(), "gtk-icon-theme-name", &pIconThemeName, (char *)NULL );
3562     aStyleSet.SetPreferredSymbolsStyleName( OUString::createFromAscii( pIconThemeName ) );
3563     g_free( pIconThemeName );
3564 
3565     //  FIXME: need some way of fetching toolbar icon size.
3566 //  aStyleSet.SetToolbarIconSize( STYLE_TOOLBAR_ICONSIZE_SMALL );
3567 
3568     const cairo_font_options_t* pNewOptions = NULL;
3569     if( GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), m_nScreen ) )
3570     {
3571 //#if !GTK_CHECK_VERSION(2,8,1)
3572 #if !GTK_CHECK_VERSION(2,9,0)
3573     static cairo_font_options_t* (*gdk_screen_get_font_options)(GdkScreen*) =
3574         (cairo_font_options_t*(*)(GdkScreen*))osl_getAsciiFunctionSymbol( GetSalData()->m_pPlugin, "gdk_screen_get_font_options" );
3575     if( gdk_screen_get_font_options != NULL )
3576 #endif
3577         pNewOptions = gdk_screen_get_font_options( pScreen );
3578     }
3579     aStyleSet.SetCairoFontOptions( pNewOptions );
3580 
3581     // finally update the collected settings
3582     rSettings.SetStyleSettings( aStyleSet );
3583 
3584     #if OSL_DEBUG_LEVEL > 1
3585     {
3586         GtkSettings* pGtkSettings = gtk_settings_get_default();
3587         GValue aValue;
3588         memset( &aValue, 0, sizeof(GValue) );
3589         g_value_init( &aValue, G_TYPE_STRING );
3590         g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
3591         const gchar* pThemeName = g_value_get_string( &aValue );
3592         std::fprintf( stderr, "Theme name is \"%s\"\n", pThemeName );
3593         g_value_unset( &aValue );
3594     }
3595     #endif
3596     GtkSettings* pGtkSettings = gtk_settings_get_default();
3597     GValue aValue;
3598     memset( &aValue, 0, sizeof(GValue) );
3599     g_value_init( &aValue, G_TYPE_STRING );
3600     g_object_get_property( G_OBJECT(pGtkSettings), "gtk-theme-name", &aValue );
3601     const gchar* pThemeName = g_value_get_string( &aValue );
3602 
3603     // default behaviour
3604     bNeedPixmapPaint = bGlobalNeedPixmapPaint;
3605     bToolbarGripWorkaround = false;
3606     bNeedButtonStyleAsEditBackgroundWorkaround = false;
3607 
3608     // setup some workarounds for "blueprint" theme
3609     if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
3610     {
3611         bNeedButtonStyleAsEditBackgroundWorkaround = true;
3612         if( GetX11SalData()->GetDisplay()->GetServerVendor() == vendor_sun )
3613         {
3614             // #i52570#, #i61532# workaround a weird paint issue;
3615             // on a Sunray Xserver sometimes painting buttons and edits
3616             // won't work when using the blueprint theme
3617             // not reproducible with simpler programs or other themes
3618             if( pThemeName && strncasecmp( pThemeName, "blueprint", 9 ) == 0 )
3619             {
3620                 bNeedPixmapPaint = true;
3621                 bToolbarGripWorkaround = true;
3622             }
3623         }
3624     }
3625     // clean up
3626     g_value_unset( &aValue );
3627 }
3628 
3629 
3630 /************************************************************************
3631  * Create a GdkPixmap filled with the contents of an area of an Xlib window
3632  ************************************************************************/
3633 
3634 GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect )
3635 {
3636     // Create a new pixmap to hold the composite of the window background and the control
3637     GdkPixmap * pPixmap     = gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 );
3638     GdkGC *  pPixmapGC  = gdk_gc_new( pPixmap );
3639 
3640     if( !pPixmap || !pPixmapGC )
3641     {
3642         if ( pPixmap )
3643             g_object_unref( pPixmap );
3644         if ( pPixmapGC )
3645             g_object_unref( pPixmapGC );
3646         std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" );
3647         return( NULL );
3648     }
3649 
3650     // Copy the background of the screen into a composite pixmap
3651     CopyScreenArea( GetXDisplay(),
3652               GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(),
3653               gdk_x11_drawable_get_xid(pPixmap),
3654               gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
3655               gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ),
3656               gdk_x11_gc_get_xgc(pPixmapGC),
3657               srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 );
3658 
3659     g_object_unref( pPixmapGC );
3660     return( pPixmap );
3661 }
3662 
3663 
3664 
3665 
3666 /************************************************************************
3667  * Copy an alpha pixmap to screen using a gc with clipping
3668  ************************************************************************/
3669 
3670 sal_Bool GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect )
3671 {
3672     // The GC can't be null, otherwise we'd have no clip region
3673     GC aFontGC = GetFontGC();
3674     if( aFontGC == NULL )
3675     {
3676         std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" );
3677         return( sal_False );
3678     }
3679 
3680     if ( !pPixmap )
3681         return( sal_False );
3682 
3683     // Copy the background of the screen into a composite pixmap
3684     CopyScreenArea( GetXDisplay(),
3685               GDK_DRAWABLE_XID(pPixmap),
3686               gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ),
3687               gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ),
3688               GetDrawable(), m_nScreen, GetVisual().GetDepth(),
3689               aFontGC,
3690               0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() );
3691 
3692     return( sal_True );
3693 }
3694 
3695 
3696 /************************************************************************
3697  * State conversion
3698  ************************************************************************/
3699 static void NWConvertVCLStateToGTKState( ControlState nVCLState,
3700             GtkStateType* nGTKState, GtkShadowType* nGTKShadow )
3701 {
3702     *nGTKShadow = GTK_SHADOW_OUT;
3703     *nGTKState = GTK_STATE_INSENSITIVE;
3704 
3705     if ( nVCLState & CTRL_STATE_ENABLED )
3706     {
3707         if ( nVCLState & CTRL_STATE_PRESSED )
3708         {
3709             *nGTKState = GTK_STATE_ACTIVE;
3710             *nGTKShadow = GTK_SHADOW_IN;
3711         }
3712         else if ( nVCLState & CTRL_STATE_ROLLOVER )
3713         {
3714             *nGTKState = GTK_STATE_PRELIGHT;
3715             *nGTKShadow = GTK_SHADOW_OUT;
3716         }
3717         else
3718         {
3719             *nGTKState = GTK_STATE_NORMAL;
3720             *nGTKShadow = GTK_SHADOW_OUT;
3721         }
3722     }
3723 }
3724 
3725 /************************************************************************
3726  * Set widget flags
3727  ************************************************************************/
3728 static void NWSetWidgetState( GtkWidget* widget, ControlState nState, GtkStateType nGtkState )
3729 {
3730     // Set to default state, then build up from there
3731     GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_DEFAULT );
3732     GTK_WIDGET_UNSET_FLAGS( widget, GTK_HAS_FOCUS );
3733     GTK_WIDGET_UNSET_FLAGS( widget, GTK_SENSITIVE );
3734     GTK_WIDGET_SET_FLAGS( widget, gWidgetDefaultFlags[(long)widget] );
3735 
3736     if ( nState & CTRL_STATE_DEFAULT )
3737         GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_DEFAULT );
3738     if ( !GTK_IS_TOGGLE_BUTTON(widget) && (nState & CTRL_STATE_FOCUSED) )
3739         GTK_WIDGET_SET_FLAGS( widget, GTK_HAS_FOCUS );
3740     if ( nState & CTRL_STATE_ENABLED )
3741         GTK_WIDGET_SET_FLAGS( widget, GTK_SENSITIVE );
3742     gtk_widget_set_state( widget, nGtkState );
3743 }
3744 
3745 /************************************************************************
3746  * Widget ensure functions - make sure cached objects are valid
3747  ************************************************************************/
3748 
3749 //-------------------------------------
3750 
3751 static void NWAddWidgetToCacheWindow( GtkWidget* widget, int nScreen )
3752 {
3753     NWFWidgetData& rData = gWidgetData[nScreen];
3754     if ( !rData.gCacheWindow || !rData.gDumbContainer )
3755     {
3756         if ( !rData.gCacheWindow )
3757         {
3758             rData.gCacheWindow = gtk_window_new( GTK_WINDOW_TOPLEVEL );
3759             GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
3760             if( pScreen )
3761                 gtk_window_set_screen( GTK_WINDOW(rData.gCacheWindow), pScreen );
3762         }
3763         if ( !rData.gDumbContainer )
3764             rData.gDumbContainer = gtk_fixed_new();
3765         gtk_container_add( GTK_CONTAINER(rData.gCacheWindow), rData.gDumbContainer );
3766         gtk_widget_realize( rData.gDumbContainer );
3767         gtk_widget_realize( rData.gCacheWindow );
3768     }
3769 
3770     gtk_container_add( GTK_CONTAINER(rData.gDumbContainer), widget );
3771     gtk_widget_realize( widget );
3772     gtk_widget_ensure_style( widget );
3773 
3774     // Store widget's default flags
3775     gWidgetDefaultFlags[ (long)widget ] = GTK_WIDGET_FLAGS( widget );
3776 }
3777 
3778 //-------------------------------------
3779 
3780 static void NWEnsureGTKButton( int nScreen )
3781 {
3782     if ( !gWidgetData[nScreen].gBtnWidget )
3783     {
3784         gWidgetData[nScreen].gBtnWidget = gtk_button_new_with_label( "" );
3785         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gBtnWidget, nScreen );
3786     }
3787 }
3788 
3789 //-------------------------------------
3790 
3791 static void NWEnsureGTKRadio( int nScreen )
3792 {
3793     if ( !gWidgetData[nScreen].gRadioWidget || !gWidgetData[nScreen].gRadioWidgetSibling )
3794     {
3795         gWidgetData[nScreen].gRadioWidget = gtk_radio_button_new( NULL );
3796         gWidgetData[nScreen].gRadioWidgetSibling = gtk_radio_button_new_from_widget( GTK_RADIO_BUTTON(gWidgetData[nScreen].gRadioWidget) );
3797         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidget, nScreen );
3798         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gRadioWidgetSibling, nScreen );
3799     }
3800 }
3801 
3802 //-------------------------------------
3803 
3804 static void NWEnsureGTKCheck( int nScreen )
3805 {
3806     if ( !gWidgetData[nScreen].gCheckWidget )
3807     {
3808         gWidgetData[nScreen].gCheckWidget = gtk_check_button_new();
3809         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gCheckWidget, nScreen );
3810     }
3811 }
3812 
3813 //-------------------------------------
3814 
3815 static void NWEnsureGTKScrollbars( int nScreen )
3816 {
3817     if ( !gWidgetData[nScreen].gScrollHorizWidget )
3818     {
3819         gWidgetData[nScreen].gScrollHorizWidget = gtk_hscrollbar_new( NULL );
3820         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollHorizWidget, nScreen );
3821     }
3822 
3823     if ( !gWidgetData[nScreen].gScrollVertWidget )
3824     {
3825         gWidgetData[nScreen].gScrollVertWidget = gtk_vscrollbar_new( NULL );
3826         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrollVertWidget, nScreen );
3827     }
3828 }
3829 
3830 //-------------------------------------
3831 
3832 static void NWEnsureGTKArrow( int nScreen )
3833 {
3834     if ( !gWidgetData[nScreen].gArrowWidget || !gWidgetData[nScreen].gDropdownWidget )
3835     {
3836         gWidgetData[nScreen].gDropdownWidget = gtk_toggle_button_new();
3837         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gDropdownWidget, nScreen );
3838         gWidgetData[nScreen].gArrowWidget = gtk_arrow_new( GTK_ARROW_DOWN, GTK_SHADOW_OUT );
3839         gtk_container_add( GTK_CONTAINER(gWidgetData[nScreen].gDropdownWidget), gWidgetData[nScreen].gArrowWidget );
3840         gtk_widget_set_rc_style( gWidgetData[nScreen].gArrowWidget );
3841         gtk_widget_realize( gWidgetData[nScreen].gArrowWidget );
3842     }
3843 }
3844 
3845 //-------------------------------------
3846 
3847 static void NWEnsureGTKEditBox( int nScreen )
3848 {
3849     if ( !gWidgetData[nScreen].gEditBoxWidget )
3850     {
3851         gWidgetData[nScreen].gEditBoxWidget = gtk_entry_new();
3852         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gEditBoxWidget, nScreen );
3853     }
3854 }
3855 
3856 //-------------------------------------
3857 
3858 static void NWEnsureGTKSpinButton( int nScreen )
3859 {
3860     if ( !gWidgetData[nScreen].gSpinButtonWidget )
3861     {
3862         GtkAdjustment *adj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 1, 1, 1, 0) );
3863         gWidgetData[nScreen].gSpinButtonWidget = gtk_spin_button_new( adj, 1, 2 );
3864 
3865         //Setting non-editable means it doesn't blink, so there's no timeouts
3866         //running around to nobble us
3867         gtk_editable_set_editable(GTK_EDITABLE(gWidgetData[nScreen].gSpinButtonWidget), false);
3868 
3869         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gSpinButtonWidget, nScreen );
3870     }
3871 }
3872 
3873 //-------------------------------------
3874 
3875 static void NWEnsureGTKNotebook( int nScreen )
3876 {
3877     if ( !gWidgetData[nScreen].gNotebookWidget )
3878     {
3879         gWidgetData[nScreen].gNotebookWidget = gtk_notebook_new();
3880         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gNotebookWidget, nScreen );
3881     }
3882 }
3883 
3884 //-------------------------------------
3885 
3886 static void NWEnsureGTKOptionMenu( int nScreen )
3887 {
3888     if ( !gWidgetData[nScreen].gOptionMenuWidget )
3889     {
3890         gWidgetData[nScreen].gOptionMenuWidget = gtk_option_menu_new();
3891         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gOptionMenuWidget, nScreen );
3892     }
3893 }
3894 
3895 //-------------------------------------
3896 
3897 static void NWEnsureGTKCombo( int nScreen )
3898 {
3899     if ( !gWidgetData[nScreen].gComboWidget )
3900     {
3901         gWidgetData[nScreen].gComboWidget = gtk_combo_new();
3902 
3903         // #i59129# Setting non-editable means it doesn't blink, so
3904         // there are no timeouts running around to nobble us
3905         gtk_editable_set_editable(GTK_EDITABLE(GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry), false);
3906 
3907         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gComboWidget, nScreen );
3908         // Must realize the ComboBox's children, since GTK
3909         // does not do this for us in GtkCombo::gtk_widget_realize()
3910         gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->button );
3911         gtk_widget_realize( GTK_COMBO(gWidgetData[nScreen].gComboWidget)->entry );
3912     }
3913 }
3914 
3915 //-------------------------------------
3916 
3917 static void NWEnsureGTKScrolledWindow( int nScreen )
3918 {
3919     if ( !gWidgetData[nScreen].gScrolledWindowWidget )
3920     {
3921         GtkAdjustment *hadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
3922         GtkAdjustment *vadj = GTK_ADJUSTMENT( gtk_adjustment_new(0, 0, 0, 0, 0, 0) );
3923 
3924         gWidgetData[nScreen].gScrolledWindowWidget = gtk_scrolled_window_new( hadj, vadj );
3925         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gScrolledWindowWidget, nScreen );
3926     }
3927 }
3928 
3929 //-------------------------------------
3930 
3931 static void NWEnsureGTKToolbar( int nScreen )
3932 {
3933     if( !gWidgetData[nScreen].gToolbarWidget )
3934     {
3935         gWidgetData[nScreen].gToolbarWidget = gtk_toolbar_new();
3936         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarWidget, nScreen );
3937         gWidgetData[nScreen].gToolbarButtonWidget = gtk_button_new();
3938         gWidgetData[nScreen].gToolbarToggleWidget = gtk_toggle_button_new();
3939 
3940         GtkReliefStyle aRelief = GTK_RELIEF_NORMAL;
3941         gtk_widget_ensure_style( gWidgetData[nScreen].gToolbarWidget );
3942         gtk_widget_style_get( gWidgetData[nScreen].gToolbarWidget,
3943                               "button_relief", &aRelief,
3944                               (char *)NULL);
3945 
3946         gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarButtonWidget), aRelief );
3947         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_FOCUS );
3948         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarButtonWidget, GTK_CAN_DEFAULT );
3949         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarButtonWidget, nScreen );
3950 
3951         gtk_button_set_relief( GTK_BUTTON(gWidgetData[nScreen].gToolbarToggleWidget), aRelief );
3952         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_FOCUS );
3953         GTK_WIDGET_UNSET_FLAGS( gWidgetData[nScreen].gToolbarToggleWidget, GTK_CAN_DEFAULT );
3954         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gToolbarToggleWidget, nScreen );
3955     }
3956     if( ! gWidgetData[nScreen].gHandleBoxWidget )
3957     {
3958         gWidgetData[nScreen].gHandleBoxWidget = gtk_handle_box_new();
3959         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHandleBoxWidget, nScreen );
3960     }
3961 }
3962 
3963 //-------------------------------------
3964 
3965 static void NWEnsureGTKMenubar( int nScreen )
3966 {
3967     if( !gWidgetData[nScreen].gMenubarWidget )
3968     {
3969         gWidgetData[nScreen].gMenubarWidget = gtk_menu_bar_new();
3970         gWidgetData[nScreen].gMenuItemMenubarWidget = gtk_menu_item_new_with_label( "b" );
3971         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenubarWidget ), gWidgetData[nScreen].gMenuItemMenubarWidget );
3972         gtk_widget_show( gWidgetData[nScreen].gMenuItemMenubarWidget );
3973         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gMenubarWidget, nScreen );
3974         gtk_widget_show( gWidgetData[nScreen].gMenubarWidget );
3975 
3976         // do what NWAddWidgetToCacheWindow does except adding to def container
3977         gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenubarWidget );
3978         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenubarWidget );
3979 
3980         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenubarWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenubarWidget );
3981     }
3982 }
3983 
3984 static void NWEnsureGTKMenu( int nScreen )
3985 {
3986     if( !gWidgetData[nScreen].gMenuWidget )
3987     {
3988         gWidgetData[nScreen].gMenuWidget              = gtk_menu_new();
3989         gWidgetData[nScreen].gMenuItemMenuWidget      = gtk_menu_item_new_with_label( "b" );
3990         gWidgetData[nScreen].gMenuItemCheckMenuWidget = gtk_check_menu_item_new_with_label( "b" );
3991         gWidgetData[nScreen].gMenuItemRadioMenuWidget = gtk_radio_menu_item_new_with_label( NULL, "b" );
3992         gWidgetData[nScreen].gImageMenuItem           = gtk_image_menu_item_new();
3993 
3994         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemMenuWidget );
3995         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemCheckMenuWidget );
3996         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gMenuItemRadioMenuWidget );
3997         gtk_menu_shell_append( GTK_MENU_SHELL( gWidgetData[nScreen].gMenuWidget ), gWidgetData[nScreen].gImageMenuItem );
3998 
3999         // do what NWAddWidgetToCacheWindow does except adding to def container
4000         gtk_widget_realize( gWidgetData[nScreen].gMenuWidget );
4001         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuWidget );
4002 
4003         gtk_widget_realize( gWidgetData[nScreen].gMenuItemMenuWidget );
4004         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemMenuWidget );
4005 
4006         gtk_widget_realize( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4007         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4008 
4009         gtk_widget_realize( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4010         gtk_widget_ensure_style( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4011 
4012         gtk_widget_realize( gWidgetData[nScreen].gImageMenuItem );
4013         gtk_widget_ensure_style( gWidgetData[nScreen].gImageMenuItem );
4014 
4015         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuWidget );
4016         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemMenuWidget );
4017         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemCheckMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemCheckMenuWidget );
4018         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gMenuItemRadioMenuWidget ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gMenuItemRadioMenuWidget );
4019         gWidgetDefaultFlags[ (long)gWidgetData[nScreen].gImageMenuItem ] = GTK_WIDGET_FLAGS( gWidgetData[nScreen].gImageMenuItem );
4020     }
4021 }
4022 
4023 static void NWEnsureGTKTooltip( int nScreen )
4024 {
4025     if( !gWidgetData[nScreen].gTooltipPopup )
4026     {
4027         gWidgetData[nScreen].gTooltipPopup = gtk_window_new (GTK_WINDOW_POPUP);
4028         GdkScreen* pScreen = gdk_display_get_screen( gdk_display_get_default(), nScreen );
4029         if( pScreen )
4030             gtk_window_set_screen( GTK_WINDOW(gWidgetData[nScreen].gTooltipPopup), pScreen );
4031         gtk_widget_set_name( gWidgetData[nScreen].gTooltipPopup, "gtk-tooltips");
4032         gtk_widget_realize( gWidgetData[nScreen].gTooltipPopup );
4033         gtk_widget_ensure_style( gWidgetData[nScreen].gTooltipPopup );
4034     }
4035 }
4036 
4037 static void NWEnsureGTKProgressBar( int nScreen )
4038 {
4039     if( !gWidgetData[nScreen].gProgressBar )
4040     {
4041         gWidgetData[nScreen].gProgressBar = gtk_progress_bar_new ();
4042         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gProgressBar, nScreen );
4043     }
4044 }
4045 
4046 static void NWEnsureGTKTreeView( int nScreen )
4047 {
4048     if( !gWidgetData[nScreen].gTreeView )
4049     {
4050         gWidgetData[nScreen].gTreeView = gtk_tree_view_new ();
4051         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gTreeView, nScreen );
4052     }
4053 }
4054 
4055 static void NWEnsureGTKSlider( int nScreen )
4056 {
4057     if( !gWidgetData[nScreen].gHScale )
4058     {
4059         gWidgetData[nScreen].gHScale = gtk_hscale_new_with_range(0, 10, 1);
4060         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gHScale, nScreen );
4061     }
4062     if( !gWidgetData[nScreen].gVScale )
4063     {
4064         gWidgetData[nScreen].gVScale = gtk_vscale_new_with_range(0, 10, 1);
4065         NWAddWidgetToCacheWindow( gWidgetData[nScreen].gVScale, nScreen );
4066     }
4067 }
4068